nexrall-code 0.5.115 → 0.5.116

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 (2) hide show
  1. package/dist/index.js +297 -91
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9921,6 +9921,8 @@ var require_client = __commonJS({
9921
9921
  Object.defineProperty(exports2, "__esModule", { value: true });
9922
9922
  exports2.API_BASE = void 0;
9923
9923
  exports2.chooseFinalContent = chooseFinalContent;
9924
+ exports2.earlyToolResolveEnabled = earlyToolResolveEnabled;
9925
+ exports2.gzipRequestsEnabled = gzipRequestsEnabled;
9924
9926
  exports2.streamChat = streamChat;
9925
9927
  exports2.cancelTurn = cancelTurn;
9926
9928
  exports2.revokeRefreshToken = revokeRefreshToken2;
@@ -9937,6 +9939,7 @@ var require_client = __commonJS({
9937
9939
  var eventsource_parser_1 = require_dist();
9938
9940
  var node_fetch_1 = __importDefault((init_src(), __toCommonJS(src_exports)));
9939
9941
  var crypto_1 = __require("crypto");
9942
+ var zlib_1 = __require("zlib");
9940
9943
  var index_1 = require_auth();
9941
9944
  var DEFAULT_API_BASE = "https://api.nexrall.com";
9942
9945
  function resolveApiBase() {
@@ -10027,6 +10030,13 @@ var require_client = __commonJS({
10027
10030
  var MAX_RETRIES = 5;
10028
10031
  var RETRY_BASE_MS = 1e3;
10029
10032
  var RETRY_MAX_MS = 3e4;
10033
+ function earlyToolResolveEnabled() {
10034
+ return process.env.NEXRALL_EARLY_TOOL_RESOLVE !== "0";
10035
+ }
10036
+ var GZIP_MIN_BYTES = 32 * 1024;
10037
+ function gzipRequestsEnabled() {
10038
+ return process.env.NEXRALL_GZIP_REQUESTS !== "0";
10039
+ }
10030
10040
  var HOUSEKEEPING_FRAMES = /* @__PURE__ */ new Set([
10031
10041
  "resumable",
10032
10042
  "runtime_context",
@@ -10101,6 +10111,14 @@ var require_client = __commonJS({
10101
10111
  let carryToolUse = [];
10102
10112
  let emittedAnythingAcrossAttempts = false;
10103
10113
  let emittedCharsAcrossAttempts = 0;
10114
+ let chatBody = null;
10115
+ const getChatBody = () => {
10116
+ if (chatBody && chatBody.turnId === turnId)
10117
+ return chatBody;
10118
+ const json = JSON.stringify({ messages, model, env: env4, editorContext, nexrallMd, mode, effort, clientType, extraTools, agents, skills, turnId, canWriteSharedMemory, hasOwnAgentStore, canSpawnSubAgents, canBrowseWeb, toolAllowlist, ...billingOverrideFields2() });
10119
+ chatBody = gzipRequestsEnabled() && json.length >= GZIP_MIN_BYTES ? { data: (0, zlib_1.gzipSync)(json, { level: 5 }), gzip: true, turnId } : { data: json, gzip: false, turnId };
10120
+ return chatBody;
10121
+ };
10104
10122
  const buildFetchArgs = () => {
10105
10123
  const signal = controller.signal;
10106
10124
  if (resuming) {
@@ -10115,12 +10133,15 @@ var require_client = __commonJS({
10115
10133
  }
10116
10134
  return [
10117
10135
  `${exports2.API_BASE}/api/code/chat`,
10118
- {
10119
- method: "POST",
10120
- headers: authHeaders(),
10121
- body: JSON.stringify({ messages, model, env: env4, editorContext, nexrallMd, mode, effort, clientType, extraTools, agents, skills, turnId, canWriteSharedMemory, hasOwnAgentStore, canSpawnSubAgents, canBrowseWeb, toolAllowlist, ...billingOverrideFields2() }),
10122
- signal
10123
- }
10136
+ (() => {
10137
+ const body = getChatBody();
10138
+ return {
10139
+ method: "POST",
10140
+ headers: body.gzip ? { ...authHeaders(), "Content-Encoding": "gzip" } : authHeaders(),
10141
+ body: body.data,
10142
+ signal
10143
+ };
10144
+ })()
10124
10145
  ];
10125
10146
  };
10126
10147
  const isRetryableStreamMsg = (m2) => {
@@ -10494,6 +10515,16 @@ var require_client = __commonJS({
10494
10515
  cache_read_input_tokens: typeof evt.cache_read_input_tokens === "number" ? evt.cache_read_input_tokens : void 0
10495
10516
  }
10496
10517
  });
10518
+ if (evt.partial !== true && completedMessage?.stopReason === "tool_use" && earlyToolResolveEnabled()) {
10519
+ clearInterval(heartbeatWatchdog);
10520
+ const drainGuard = setTimeout(() => {
10521
+ stream.destroy?.();
10522
+ }, HEARTBEAT_TIMEOUT_MS);
10523
+ drainGuard.unref?.();
10524
+ stream.once("end", () => clearTimeout(drainGuard));
10525
+ stream.once("close", () => clearTimeout(drainGuard));
10526
+ resolve4();
10527
+ }
10497
10528
  }
10498
10529
  break;
10499
10530
  }
@@ -10808,7 +10839,7 @@ var require_client = __commonJS({
10808
10839
  const data = await response.json();
10809
10840
  return {
10810
10841
  models: Array.isArray(data.models) ? data.models : [],
10811
- defaultModel: typeof data.defaultModel === "string" ? data.defaultModel : "claude-sonnet-5"
10842
+ defaultModel: typeof data.defaultModel === "string" ? data.defaultModel : "deepseek-flash"
10812
10843
  };
10813
10844
  }
10814
10845
  async function getUsageDaily(days = 30) {
@@ -12130,7 +12161,7 @@ var require_agentTypes = __commonJS({
12130
12161
  // edit Z directly" does better work, and withholding it meant every sub-agent
12131
12162
  // rediscovered project conventions from scratch. Writing is a different thing
12132
12163
  // entirely — memory is durable, cross-session, SHARED state, while sub-agents run
12133
- // up to 4-wide in parallel with their reasoning hidden from the user. A wrong fact
12164
+ // up to 10-wide (configurable) in parallel with their reasoning hidden from the user. A wrong fact
12134
12165
  // written there is invisible and permanent, and it competes for a capped, shared
12135
12166
  // budget that gets periodically condensed.
12136
12167
  //
@@ -13978,41 +14009,100 @@ var require_tsLangService = __commonJS({
13978
14009
  return null;
13979
14010
  }
13980
14011
  var _services = /* @__PURE__ */ new Map();
13981
- function getService(workDir) {
13982
- const cached = _services.get(workDir);
13983
- if (cached)
13984
- return cached;
14012
+ function findGoverningConfig(ts, workDir, filePath) {
14013
+ try {
14014
+ if (filePath) {
14015
+ const near = ts.findConfigFile(path8.dirname(filePath), ts.sys.fileExists, "tsconfig.json");
14016
+ if (near)
14017
+ return near;
14018
+ }
14019
+ return ts.findConfigFile(workDir, ts.sys.fileExists, "tsconfig.json") || void 0;
14020
+ } catch {
14021
+ return void 0;
14022
+ }
14023
+ }
14024
+ var MAX_ROOT_FILES = 2e4;
14025
+ var ROOT_RESCAN_MS = Number(process.env.NEXRALL_TS_ROOT_RESCAN_MS ?? 2e3);
14026
+ function getService(workDir, filePath) {
13985
14027
  const ts = loadTs(workDir);
13986
14028
  if (!ts)
13987
14029
  return null;
14030
+ const cfgPath = findGoverningConfig(ts, workDir, filePath);
14031
+ const key = cfgPath ?? workDir;
14032
+ const cached = _services.get(key);
14033
+ if (cached)
14034
+ return cached;
13988
14035
  const versions = /* @__PURE__ */ new Map();
13989
14036
  const snapshots = /* @__PURE__ */ new Map();
14037
+ const mtimes = /* @__PURE__ */ new Map();
14038
+ const mtimeOf = (fileName) => {
14039
+ try {
14040
+ return fs9.statSync(fileName).mtimeMs;
14041
+ } catch {
14042
+ return -1;
14043
+ }
14044
+ };
13990
14045
  const readSource = (fileName) => {
13991
14046
  const cachedSrc = snapshots.get(fileName);
13992
- if (cachedSrc !== void 0)
14047
+ const m2 = mtimeOf(fileName);
14048
+ if (cachedSrc !== void 0 && mtimes.get(fileName) === m2)
13993
14049
  return cachedSrc;
13994
14050
  try {
13995
14051
  const src = fs9.readFileSync(fileName, "utf-8");
13996
14052
  snapshots.set(fileName, src);
14053
+ mtimes.set(fileName, m2);
13997
14054
  return src;
13998
14055
  } catch {
13999
- return void 0;
14056
+ return cachedSrc;
14000
14057
  }
14001
14058
  };
14002
14059
  let options = { allowJs: true, checkJs: false, target: 99, module: 99 };
14003
- try {
14004
- const cfgPath = ts.findConfigFile(workDir, ts.sys.fileExists, "tsconfig.json");
14005
- if (cfgPath) {
14006
- const parsed = ts.readConfigFile(cfgPath, ts.sys.readFile);
14007
- const conf = ts.parseJsonConfigFileContent(parsed.config ?? {}, ts.sys, path8.dirname(cfgPath));
14008
- if (conf.options)
14060
+ let rootFiles = /* @__PURE__ */ new Set();
14061
+ const addConfig = (cfg, depth) => {
14062
+ try {
14063
+ const parsed = ts.readConfigFile(cfg, ts.sys.readFile);
14064
+ const conf = ts.parseJsonConfigFileContent(parsed.config ?? {}, ts.sys, path8.dirname(cfg));
14065
+ if (depth === 0 && conf.options)
14009
14066
  options = { ...conf.options, allowJs: true };
14067
+ for (const f3 of conf.fileNames ?? []) {
14068
+ if (rootFiles.size >= MAX_ROOT_FILES)
14069
+ break;
14070
+ rootFiles.add(path8.resolve(f3));
14071
+ }
14072
+ if (depth === 0 && rootFiles.size === 0) {
14073
+ for (const ref of conf.projectReferences ?? []) {
14074
+ const refCfg = ts.resolveProjectReferencePath ? ts.resolveProjectReferencePath(ref) : ref.path;
14075
+ if (refCfg && ts.sys.fileExists(refCfg))
14076
+ addConfig(refCfg, depth + 1);
14077
+ }
14078
+ }
14079
+ } catch {
14010
14080
  }
14011
- } catch {
14012
- }
14081
+ };
14082
+ if (cfgPath)
14083
+ addConfig(cfgPath, 0);
14084
+ let rootsScannedAt = Date.now();
14085
+ const refreshRoots = () => {
14086
+ if (!cfgPath || Date.now() - rootsScannedAt < ROOT_RESCAN_MS)
14087
+ return;
14088
+ rootsScannedAt = Date.now();
14089
+ const prev = rootFiles;
14090
+ rootFiles = /* @__PURE__ */ new Set();
14091
+ addConfig(cfgPath, 0);
14092
+ if (rootFiles.size === 0)
14093
+ rootFiles = prev;
14094
+ };
14013
14095
  const host = {
14014
- getScriptFileNames: () => Array.from(versions.keys()),
14015
- getScriptVersion: (f3) => String(versions.get(f3) ?? 0),
14096
+ getScriptFileNames: () => {
14097
+ refreshRoots();
14098
+ if (versions.size === 0)
14099
+ return Array.from(rootFiles);
14100
+ const all = new Set(rootFiles);
14101
+ for (const f3 of versions.keys())
14102
+ all.add(f3);
14103
+ return Array.from(all);
14104
+ },
14105
+ getScriptVersion: (f3) => `${versions.get(f3) ?? 0}:${mtimeOf(f3)}`,
14016
14106
  getScriptSnapshot: (f3) => {
14017
14107
  const src = readSource(f3);
14018
14108
  return src === void 0 ? void 0 : ts.ScriptSnapshot.fromString(src);
@@ -14028,7 +14118,7 @@ var require_tsLangService = __commonJS({
14028
14118
  };
14029
14119
  const service = ts.createLanguageService(host, ts.createDocumentRegistry());
14030
14120
  const svc = { ts, service, root: workDir, versions, snapshots };
14031
- _services.set(workDir, svc);
14121
+ _services.set(key, svc);
14032
14122
  return svc;
14033
14123
  }
14034
14124
  function ensureFile(svc, absPath) {
@@ -14069,7 +14159,7 @@ var require_tsLangService = __commonJS({
14069
14159
  return r2.startsWith("..") ? abs : r2;
14070
14160
  }
14071
14161
  function tsGoToDefinition(deps) {
14072
- const svc = getService(deps.workDir);
14162
+ const svc = getService(deps.workDir, deps.filePath);
14073
14163
  if (!svc)
14074
14164
  return null;
14075
14165
  if (!ensureFile(svc, deps.filePath))
@@ -14093,7 +14183,7 @@ var require_tsLangService = __commonJS({
14093
14183
  ${out.join("\n")}` };
14094
14184
  }
14095
14185
  function tsFindReferences(deps) {
14096
- const svc = getService(deps.workDir);
14186
+ const svc = getService(deps.workDir, deps.filePath);
14097
14187
  if (!svc)
14098
14188
  return null;
14099
14189
  if (!ensureFile(svc, deps.filePath))
@@ -14121,7 +14211,7 @@ ${out.join("\n")}` };
14121
14211
  ${lines.join("\n")}` };
14122
14212
  }
14123
14213
  function tsGetHover(deps) {
14124
- const svc = getService(deps.workDir);
14214
+ const svc = getService(deps.workDir, deps.filePath);
14125
14215
  if (!svc)
14126
14216
  return null;
14127
14217
  if (!ensureFile(svc, deps.filePath))
@@ -101394,6 +101484,8 @@ var require_executor = __commonJS({
101394
101484
  };
101395
101485
  }();
101396
101486
  Object.defineProperty(exports2, "__esModule", { value: true });
101487
+ exports2.capExternalOutput = capExternalOutput;
101488
+ exports2.runCapture = runCapture;
101397
101489
  exports2.globToRegex = globToRegex;
101398
101490
  exports2.executeTool = executeTool;
101399
101491
  var fs9 = __importStar(__require("fs"));
@@ -101688,7 +101780,7 @@ Resolve the conflict (remove <<<<<<< / ======= / >>>>>>> markers and keep the in
101688
101780
  if (isNew) {
101689
101781
  return { output: `Created ${resolved} (${lines} lines, ${bytes} bytes)${sec}`, linesAdded: lines, linesRemoved: 0 };
101690
101782
  }
101691
- const xfile = crossFileBreakageWarning(resolved, normalizeLF(priorContent), normalizeLF(content), workDir ?? process.cwd());
101783
+ const xfile = await crossFileBreakageWarning(resolved, normalizeLF(priorContent), normalizeLF(content), workDir ?? process.cwd());
101692
101784
  let tiMarker = "";
101693
101785
  const ti = (0, testIntegrity_1.analyzeTestEdit)(resolved, normalizeLF(priorContent), normalizeLF(content));
101694
101786
  if (ti.suspicious)
@@ -102216,17 +102308,104 @@ ${body}` : void 0 }));
102216
102308
  child.on("close", () => clearInterval(pollAbort));
102217
102309
  });
102218
102310
  }
102311
+ function capExternalOutput(output, label, maxChars = MAX_OUTPUT_CHARS) {
102312
+ if (output.length <= maxChars)
102313
+ return output;
102314
+ let spillNote = "";
102315
+ try {
102316
+ fs9.mkdirSync(SPILL_DIR, { recursive: true });
102317
+ const safe = label.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 60);
102318
+ const spillPath = path8.join(SPILL_DIR, `${safe}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.log`);
102319
+ fs9.writeFileSync(spillPath, (0, safeSlice_1.sliceSafeEnd)(output, MAX_SPILL_BYTES));
102320
+ spillNote = ` Full output (${output.length} chars) saved to ${spillPath} \u2014 use read_file with offset/limit to inspect any section.`;
102321
+ } catch {
102322
+ }
102323
+ const headLen = Math.floor(maxChars * 0.7);
102324
+ const tailLen = maxChars - headLen;
102325
+ const omitted = output.length - headLen - tailLen;
102326
+ return `${(0, safeSlice_1.sliceSafeEnd)(output, headLen)}
102327
+
102328
+ [\u2026 ${omitted} chars omitted.${spillNote}]
102329
+
102330
+ ${(0, safeSlice_1.sliceSafeStart)(output, output.length - tailLen)}`;
102331
+ }
102332
+ function runCapture(cmd, args, opts) {
102333
+ return new Promise((resolve4) => {
102334
+ let stdout = "";
102335
+ let stderr = "";
102336
+ let bytes = 0;
102337
+ let error;
102338
+ let settled = false;
102339
+ let child;
102340
+ try {
102341
+ child = (0, child_process_1.spawn)(cmd, args, { cwd: opts.cwd, stdio: ["ignore", "pipe", "pipe"] });
102342
+ } catch (e2) {
102343
+ resolve4({ stdout: "", stderr: "", status: null, signal: null, error: e2 });
102344
+ return;
102345
+ }
102346
+ const finish = (status, signal) => {
102347
+ if (settled)
102348
+ return;
102349
+ settled = true;
102350
+ clearTimeout(timer);
102351
+ resolve4({ stdout, stderr, status, signal, ...error ? { error } : {} });
102352
+ };
102353
+ const kill = (code) => {
102354
+ if (!error)
102355
+ error = Object.assign(new Error(`${cmd} ${code}`), { code });
102356
+ try {
102357
+ child.kill("SIGTERM");
102358
+ } catch {
102359
+ }
102360
+ };
102361
+ const timer = setTimeout(() => kill("ETIMEDOUT"), opts.timeout);
102362
+ child.stdout.setEncoding("utf-8");
102363
+ child.stderr.setEncoding("utf-8");
102364
+ child.stdout.on("data", (chunk) => {
102365
+ if (error)
102366
+ return;
102367
+ bytes += Buffer.byteLength(chunk);
102368
+ if (bytes > opts.maxBuffer) {
102369
+ stdout += chunk.slice(0, Math.max(0, chunk.length - (bytes - opts.maxBuffer)));
102370
+ kill("ENOBUFS");
102371
+ return;
102372
+ }
102373
+ stdout += chunk;
102374
+ });
102375
+ child.stderr.on("data", (chunk) => {
102376
+ if (stderr.length < 64 * 1024)
102377
+ stderr += chunk;
102378
+ });
102379
+ child.on("error", (e2) => {
102380
+ if (!error)
102381
+ error = e2;
102382
+ finish(null, null);
102383
+ });
102384
+ child.on("close", (code, signal) => finish(code, signal));
102385
+ });
102386
+ }
102219
102387
  var _rgChecked = false;
102220
102388
  var _rgAvailable = false;
102389
+ var _rgBin = "rg";
102221
102390
  function ripgrepAvailable() {
102222
102391
  if (!_rgChecked) {
102223
- const probe = (0, child_process_1.spawnSync)("rg", ["--version"], { encoding: "utf-8", timeout: 3e3 });
102224
- _rgAvailable = probe.status === 0;
102225
102392
  _rgChecked = true;
102393
+ const candidates = [process.env.NEXRALL_RG_PATH, "rg"].filter((c) => !!c);
102394
+ for (const bin of candidates) {
102395
+ const probe = (0, child_process_1.spawnSync)(bin, ["--version"], { encoding: "utf-8", timeout: 3e3 });
102396
+ if (probe.status === 0) {
102397
+ _rgBin = bin;
102398
+ _rgAvailable = true;
102399
+ break;
102400
+ }
102401
+ }
102226
102402
  }
102227
102403
  return _rgAvailable;
102228
102404
  }
102229
- function crossFileBreakageWarning(editedAbsPath, oldContent, newContent, workDir) {
102405
+ function rgBin() {
102406
+ return _rgBin;
102407
+ }
102408
+ async function crossFileBreakageWarning(editedAbsPath, oldContent, newContent, workDir) {
102230
102409
  if (process.env.NEXRALL_CROSSFILE_CHECK === "0")
102231
102410
  return "";
102232
102411
  let removed;
@@ -102246,8 +102425,8 @@ ${body}` : void 0 }));
102246
102425
  })();
102247
102426
  const hits = [];
102248
102427
  const MAX_SYMBOLS = 8;
102249
- for (const sym of removed.slice(0, MAX_SYMBOLS)) {
102250
- const refs = scanReferences(sym.name, workDir, editedReal);
102428
+ const scanned = await Promise.all(removed.slice(0, MAX_SYMBOLS).map(async (sym) => ({ sym, refs: await scanReferences(sym.name, workDir, editedReal) })));
102429
+ for (const { sym, refs } of scanned) {
102251
102430
  if (refs.length) {
102252
102431
  const shown = refs.slice(0, 3).map((r2) => ` ${r2}`).join("\n");
102253
102432
  const more = refs.length > 3 ? `
@@ -102264,44 +102443,26 @@ ${shown}${more}`);
102264
102443
  ` + hits.join("\n") + `
102265
102444
  Update these call-sites (or restore the symbol), then run a build/typecheck to confirm nothing is broken.`;
102266
102445
  }
102267
- function scanReferences(name, workDir, excludeRealPath) {
102446
+ async function scanReferences(name, workDir, excludeRealPath) {
102268
102447
  const pattern = `\\b${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`;
102269
102448
  const files = /* @__PURE__ */ new Set();
102270
102449
  try {
102271
- if (ripgrepAvailable()) {
102272
- const r2 = (0, child_process_1.spawnSync)("rg", ["-l", "--no-messages", "-e", pattern, "."], {
102273
- cwd: workDir,
102274
- encoding: "utf-8",
102275
- timeout: 8e3,
102276
- maxBuffer: 8 * 1024 * 1024
102277
- });
102278
- if (r2.stdout)
102279
- for (const line of r2.stdout.split("\n")) {
102280
- if (line.trim())
102281
- files.add(line.trim());
102282
- }
102283
- } else {
102284
- const r2 = (0, child_process_1.spawnSync)("grep", [
102285
- "-rlI",
102286
- "--exclude-dir=node_modules",
102287
- "--exclude-dir=.git",
102288
- "--exclude-dir=dist",
102289
- "--exclude-dir=.next",
102290
- "-E",
102291
- pattern,
102292
- "."
102293
- ], {
102294
- cwd: workDir,
102295
- encoding: "utf-8",
102296
- timeout: 8e3,
102297
- maxBuffer: 8 * 1024 * 1024
102298
- });
102299
- if (r2.stdout)
102300
- for (const line of r2.stdout.split("\n")) {
102301
- if (line.trim())
102302
- files.add(line.trim());
102303
- }
102304
- }
102450
+ const opts = { cwd: workDir, timeout: 8e3, maxBuffer: 8 * 1024 * 1024 };
102451
+ const r2 = ripgrepAvailable() ? await runCapture(rgBin(), ["-l", "--no-messages", "-e", pattern, "."], opts) : await runCapture("grep", [
102452
+ "-rlI",
102453
+ "--exclude-dir=node_modules",
102454
+ "--exclude-dir=.git",
102455
+ "--exclude-dir=dist",
102456
+ "--exclude-dir=.next",
102457
+ "-E",
102458
+ pattern,
102459
+ "."
102460
+ ], opts);
102461
+ if (r2.stdout)
102462
+ for (const line of r2.stdout.split("\n")) {
102463
+ if (line.trim())
102464
+ files.add(line.trim());
102465
+ }
102305
102466
  } catch {
102306
102467
  return [];
102307
102468
  }
@@ -102334,7 +102495,8 @@ Update these call-sites (or restore the symbol), then run a build/typecheck to c
102334
102495
  if (searchType === "filename") {
102335
102496
  const matches = [];
102336
102497
  const patternLower = pattern.toLowerCase();
102337
- walkDir(resolved, (filePath) => {
102498
+ const listing = await listFiles(resolved);
102499
+ listing.files.forEach((filePath) => {
102338
102500
  const name = path8.basename(filePath);
102339
102501
  const nameLower = name.toLowerCase();
102340
102502
  const rel = path8.relative(resolved, filePath).replace(/\\/g, "/");
@@ -102352,6 +102514,9 @@ Update these call-sites (or restore the symbol), then run a build/typecheck to c
102352
102514
  }).join("\n");
102353
102515
  if (out.length > MAX_OUTPUT_CHARS)
102354
102516
  out = (0, safeSlice_1.sliceSafeEnd)(out, MAX_OUTPUT_CHARS) + "\n[Truncated]";
102517
+ if (listing.truncated)
102518
+ out += `
102519
+ [Scan stopped after ${WALK_MAX_FILES.toLocaleString("en-US")} files \u2014 narrow the path for complete results.]`;
102355
102520
  return { output: out };
102356
102521
  } else {
102357
102522
  const SEARCH_MAX_BUFFER = 64 * 1024 * 1024;
@@ -102359,7 +102524,7 @@ Update these call-sites (or restore the symbol), then run a build/typecheck to c
102359
102524
  const relTarget = path8.relative(base, resolved);
102360
102525
  const inside = !relTarget.startsWith("..") && !path8.isAbsolute(relTarget);
102361
102526
  const target = inside ? relTarget || "." : resolved;
102362
- const spawnOpts = { encoding: "utf-8", timeout: DEFAULT_TIMEOUT_MS, maxBuffer: SEARCH_MAX_BUFFER, cwd: base };
102527
+ const spawnOpts = { timeout: DEFAULT_TIMEOUT_MS, maxBuffer: SEARCH_MAX_BUFFER, cwd: base };
102363
102528
  let result;
102364
102529
  if (ripgrepAvailable()) {
102365
102530
  const args = filesOnly ? ["--files-with-matches", "--color=never", "--hidden", "--glob", "!.git"] : [
@@ -102381,7 +102546,7 @@ Update these call-sites (or restore the symbol), then run a build/typecheck to c
102381
102546
  if (include)
102382
102547
  args.push("--glob", include);
102383
102548
  args.push("-m", "200", "--regexp", pattern, target);
102384
- result = (0, child_process_1.spawnSync)("rg", args, spawnOpts);
102549
+ result = await runCapture(rgBin(), args, spawnOpts);
102385
102550
  } else {
102386
102551
  const args = [filesOnly ? "-rlE" : "-rnE", "--binary-files=without-match", "--color=never"];
102387
102552
  if (ignoreCase)
@@ -102391,13 +102556,13 @@ Update these call-sites (or restore the symbol), then run a build/typecheck to c
102391
102556
  if (include)
102392
102557
  args.push(`--include=${include}`);
102393
102558
  args.push("--exclude-dir=.git", "--exclude-dir=node_modules", "--exclude-dir=dist", "--exclude-dir=.next", "--exclude-dir=__pycache__", "--exclude-dir=.turbo", "--exclude-dir=coverage", "--exclude-dir=.cache", "--exclude-dir=.venv", "--exclude-dir=venv", "-m", "200", pattern, target);
102394
- result = (0, child_process_1.spawnSync)("grep", args, spawnOpts);
102559
+ result = await runCapture("grep", args, spawnOpts);
102395
102560
  }
102396
102561
  let output = (result.stdout ?? "").replace(/^\.\//gm, "");
102397
102562
  const stderr = result.stderr ?? "";
102398
102563
  const spawnErr = result.error;
102399
102564
  if (spawnErr) {
102400
- if (spawnErr.code === "ETIMEDOUT" || result.signal === "SIGTERM") {
102565
+ if (spawnErr.code === "ETIMEDOUT" || result.signal === "SIGTERM" && spawnErr.code !== "ENOBUFS") {
102401
102566
  const partial = output ? `
102402
102567
 
102403
102568
  Partial results before timeout:
@@ -102413,7 +102578,7 @@ ${globalCapMatches(output)}` : "";
102413
102578
  if (result.status === 1 && !output)
102414
102579
  return { output: "No matches found." };
102415
102580
  if (result.status !== 0 && result.status !== 1) {
102416
- const hint = /parenthes|bracket|brace|Unmatched|repetition-operator|invalid regex/i.test(stderr) ? ' \u2014 the pattern has invalid/unbalanced regex syntax. If you meant to match literal parentheses/brackets, escape them (e.g. "\\(", "\\)"), or simplify the pattern.' : "";
102581
+ const hint = /parenthes|bracket|brace|Unmatched|unclosed|repetition-operator|invalid regex/i.test(stderr) ? ' \u2014 the pattern has invalid/unbalanced regex syntax. If you meant to match literal parentheses/brackets, escape them (e.g. "\\(", "\\)"), or simplify the pattern.' : "";
102417
102582
  return { error: (stderr || "search failed").trim() + hint };
102418
102583
  }
102419
102584
  if (filesOnly) {
@@ -102495,11 +102660,36 @@ ${globalCapMatches(output)}` : "";
102495
102660
  ".idea",
102496
102661
  ".DS_Store"
102497
102662
  ]);
102663
+ var WALK_MAX_FILES = 5e4;
102664
+ async function listFiles(root) {
102665
+ if (ripgrepAvailable()) {
102666
+ const args = ["--files", "--hidden", "--follow", "--no-messages", "--color=never"];
102667
+ for (const d of WALK_SKIP_DIRS)
102668
+ args.push("--glob", `!**/${d}/**`);
102669
+ args.push(".");
102670
+ const r2 = await runCapture(rgBin(), args, { cwd: root, timeout: DEFAULT_TIMEOUT_MS, maxBuffer: 64 * 1024 * 1024 });
102671
+ if (!r2.error && (r2.status === 0 || r2.status === 1 || r2.status === 2 && r2.stdout)) {
102672
+ const files2 = r2.stdout.split("\n").filter(Boolean).map((f3) => path8.join(root, f3.replace(/^\.\//, "")));
102673
+ return { files: files2, truncated: false };
102674
+ }
102675
+ }
102676
+ const files = [];
102677
+ let truncated = false;
102678
+ walkDir(root, (f3) => {
102679
+ if (files.length >= WALK_MAX_FILES) {
102680
+ truncated = true;
102681
+ return false;
102682
+ }
102683
+ files.push(f3);
102684
+ return true;
102685
+ });
102686
+ return { files, truncated };
102687
+ }
102498
102688
  function walkDir(dirPath, callback, _visited = /* @__PURE__ */ new Set()) {
102499
102689
  try {
102500
102690
  const real = fs9.realpathSync(dirPath);
102501
102691
  if (_visited.has(real))
102502
- return;
102692
+ return true;
102503
102693
  _visited.add(real);
102504
102694
  const entries = fs9.readdirSync(dirPath, { withFileTypes: true });
102505
102695
  for (const entry of entries) {
@@ -102514,13 +102704,15 @@ ${globalCapMatches(output)}` : "";
102514
102704
  if (isDir) {
102515
102705
  if (WALK_SKIP_DIRS.has(entry.name))
102516
102706
  continue;
102517
- walkDir(fullPath, callback, _visited);
102518
- } else {
102519
- callback(fullPath);
102707
+ if (walkDir(fullPath, callback, _visited) === false)
102708
+ return false;
102709
+ } else if (callback(fullPath) === false) {
102710
+ return false;
102520
102711
  }
102521
102712
  }
102522
102713
  } catch {
102523
102714
  }
102715
+ return true;
102524
102716
  }
102525
102717
  async function createDirectory(input, workDir) {
102526
102718
  const dirPath = typeof input.path === "string" ? input.path : "";
@@ -102678,7 +102870,7 @@ ${globalCapMatches(output)}` : "";
102678
102870
  const diff3 = buildDiff(filePath, oldNorm, newNorm, origNorm);
102679
102871
  const linesBefore = origNorm.split("\n").length;
102680
102872
  const linesAfter = updated.split("\n").length;
102681
- const xfile = crossFileBreakageWarning(resolved, origNorm, normalizeLF(updated), workDir ?? process.cwd());
102873
+ const xfile = await crossFileBreakageWarning(resolved, origNorm, normalizeLF(updated), workDir ?? process.cwd());
102682
102874
  const sec = (0, securityLint_1.securityNoteText)((0, securityLint_1.checkSecurity)(newNorm));
102683
102875
  return {
102684
102876
  output: `Edited ${resolved} (${linesBefore} \u2192 ${linesAfter} lines)
@@ -103054,7 +103246,7 @@ ${body}${truncNote}
103054
103246
  }
103055
103247
  const finalContent = wasCRLF ? content.replace(/\n/g, "\r\n") : content;
103056
103248
  atomicWritePreservingMode(resolved, finalContent, pre.mode);
103057
- const xfile = crossFileBreakageWarning(resolved, originalNorm, content, workDir ?? process.cwd());
103249
+ const xfile = await crossFileBreakageWarning(resolved, originalNorm, content, workDir ?? process.cwd());
103058
103250
  const sec = (0, securityLint_1.securityNoteText)((0, securityLint_1.checkSecurity)(insertedText.join("\n")));
103059
103251
  return {
103060
103252
  output: `Applied ${edits.length} edit(s) to ${resolved}:
@@ -103078,14 +103270,17 @@ ${d}`).join("\n") + xfile + sec,
103078
103270
  const matches = [];
103079
103271
  const regex2 = globToRegex(pattern);
103080
103272
  const useBasename = !pattern.includes("/") && !pattern.includes("**");
103081
- walkDir(resolved, (filePath) => {
103273
+ const listing = await listFiles(resolved);
103274
+ for (const filePath of listing.files) {
103082
103275
  const rel = path8.relative(resolved, filePath).replace(/\\/g, "/");
103083
103276
  if (regex2.test(rel) || useBasename && regex2.test(path8.basename(filePath))) {
103084
103277
  matches.push(filePath);
103085
103278
  }
103086
- });
103279
+ }
103280
+ const scanNote = listing.truncated ? `
103281
+ [Scan stopped after ${WALK_MAX_FILES.toLocaleString("en-US")} files \u2014 narrow the path for complete results.]` : "";
103087
103282
  if (!matches.length)
103088
- return { output: `No files matched pattern: ${pattern}` };
103283
+ return { output: `No files matched pattern: ${pattern}${scanNote}` };
103089
103284
  const mtime = (f3) => {
103090
103285
  try {
103091
103286
  return fs9.statSync(f3).mtimeMs;
@@ -103098,7 +103293,7 @@ ${d}`).join("\n") + xfile + sec,
103098
103293
  const more = sorted.length > shown.length ? `
103099
103294
  [${sorted.length - shown.length} more not shown \u2014 narrow the pattern or path]` : "";
103100
103295
  return { output: `${matches.length} file(s) matched "${pattern}" under ${resolved}:
103101
- ${shown.join("\n")}${more}` };
103296
+ ${shown.join("\n")}${more}${scanNote}` };
103102
103297
  } catch (err) {
103103
103298
  return { error: err.message };
103104
103299
  }
@@ -106220,6 +106415,7 @@ var require_loop = __commonJS({
106220
106415
  exports2.contextWindowFor = contextWindowFor2;
106221
106416
  exports2.compactionLimits = compactionLimits;
106222
106417
  exports2.compactionThresholds = compactionThresholds2;
106418
+ exports2.pruneReclaimFloor = pruneReclaimFloor;
106223
106419
  exports2.estimateBodyBytes = estimateBodyBytes2;
106224
106420
  exports2.allowsTestOnlyWrite = allowsTestOnlyWrite;
106225
106421
  exports2.findSafeCutIndex = findSafeCutIndex;
@@ -106579,9 +106775,10 @@ ${ctx.repeatError}
106579
106775
  const abs = raw.map((p) => workDir ? path8.resolve(workDir, p) : p);
106580
106776
  return abs.length ? abs : [name];
106581
106777
  }
106582
- var DEFAULT_MAX_CONCURRENT_SUBTASKS = 4;
106778
+ var DEFAULT_MAX_CONCURRENT_SUBTASKS = 10;
106779
+ var HARD_MAX_CONCURRENT_SUBTASKS = 32;
106583
106780
  function resolveMaxConcurrentSubtasks(settingsRaw = {}) {
106584
- const clamp = (n) => Math.max(1, Math.min(Math.floor(n), 16));
106781
+ const clamp = (n) => Math.max(1, Math.min(Math.floor(n), HARD_MAX_CONCURRENT_SUBTASKS));
106585
106782
  const fromEnv = Number(process.env.NEXRALL_MAX_CONCURRENT_SUBTASKS);
106586
106783
  if (Number.isFinite(fromEnv) && fromEnv > 0)
106587
106784
  return clamp(fromEnv);
@@ -107058,12 +107255,12 @@ ${sk.body.trim()}` : `# Preloaded skill: ${n}
107058
107255
  }).join("\n\n");
107059
107256
  }
107060
107257
  const subNexrallMd = [
107258
+ inheritedMd,
107061
107259
  SUBAGENT_PREAMBLE,
107062
107260
  agent ? `# Sub-agent role: ${agent.name}
107063
107261
  ${agent.prompt}` : "",
107064
107262
  preloadedSkills,
107065
- agentMemoryNotes,
107066
- inheritedMd
107263
+ agentMemoryNotes
107067
107264
  ].filter(Boolean).join("\n\n---\n\n");
107068
107265
  const testFilesOnly = !!agent?.testFilesOnly || !!options._testFilesOnly;
107069
107266
  const allowed = intersectAllowlists(agent?.tools ? new Set(agent.tools) : null, options._allowedTools);
@@ -107498,6 +107695,12 @@ ${partial}` : "",
107498
107695
  return { prune: prune / contextWindow, compact: compact / contextWindow };
107499
107696
  }
107500
107697
  var PRUNE_MIN_RECLAIM_BYTES = 96 * 1024;
107698
+ var PRUNE_MIN_RECLAIM_BYTES_COLD = 16 * 1024;
107699
+ var CACHE_COLD_AFTER_MS = 5 * 6e4;
107700
+ var _lastApiCallEndedAt = /* @__PURE__ */ new Map();
107701
+ function pruneReclaimFloor(lastCallEndedAt, now = Date.now()) {
107702
+ return lastCallEndedAt !== void 0 && now - lastCallEndedAt >= CACHE_COLD_AFTER_MS ? PRUNE_MIN_RECLAIM_BYTES_COLD : PRUNE_MIN_RECLAIM_BYTES;
107703
+ }
107501
107704
  var COMPACT_KEEP_MIN = 6;
107502
107705
  var COMPACT_MIN_RECLAIM_BYTES = 32 * 1024;
107503
107706
  var COMPACT_MAX_FAILURES = 3;
@@ -108110,7 +108313,8 @@ Continue the work from here.` }] });
108110
108313
  const tokenPressure = lastPromptTokens > compactLimits.compact;
108111
108314
  let bytePressure = bodyBytes > MAX_BODY_BYTES;
108112
108315
  if (autoCompact && !compacting && (prunePressure || bytePressure) && messages.length > PRUNE_KEEP_RECENT + 2) {
108113
- const reclaimed = pruneOldToolResults(messages, PRUNE_MIN_RECLAIM_BYTES);
108316
+ const floor = depth === 0 ? pruneReclaimFloor(_lastApiCallEndedAt.get(options.sessionId || PROCESS_BUDGET_KEY)) : PRUNE_MIN_RECLAIM_BYTES;
108317
+ const reclaimed = pruneOldToolResults(messages, floor);
108114
108318
  if (reclaimed > 0) {
108115
108319
  bodyBytes = estimateBodyBytes2(messages);
108116
108320
  bytePressure = bodyBytes > MAX_BODY_BYTES;
@@ -108225,6 +108429,8 @@ Continue the work from here.` }] });
108225
108429
  allowRestartAfterRender: !!options.onStreamRestart
108226
108430
  }, onEvent);
108227
108431
  options.onApiCallDuration?.(Date.now() - _apiCallStartedAt);
108432
+ if (depth === 0)
108433
+ _lastApiCallEndedAt.set(options.sessionId || PROCESS_BUDGET_KEY, Date.now());
108228
108434
  if (pendingRuntimeContext)
108229
108435
  persistRuntimeContext(messages, sentUserIdx, pendingRuntimeContext);
108230
108436
  } catch (err) {
@@ -108462,7 +108668,7 @@ Continue the work from here.` }] });
108462
108668
  result = external;
108463
108669
  } else if (options.mcpManager?.isMcpTool(name)) {
108464
108670
  const mcpOutput = await stopAwaiting(options.mcpManager.callTool(name, input, options.abortSignal), options.abortSignal);
108465
- result = mcpOutput === STOP_TIMEOUT_RESULT ? STOP_TIMEOUT_RESULT : { output: mcpOutput ?? "" };
108671
+ result = mcpOutput === STOP_TIMEOUT_RESULT ? STOP_TIMEOUT_RESULT : { output: (0, executor_1.capExternalOutput)(mcpOutput ?? "", `mcp-${name}`) };
108466
108672
  } else {
108467
108673
  options.checkpointManager?.recordBeforeMutation(name, input);
108468
108674
  const onStream = options.onToolStreamChunk ? (chunk) => options.onToolStreamChunk(name, chunk, void 0, toolMeta) : void 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexrall-code",
3
- "version": "0.5.115",
3
+ "version": "0.5.116",
4
4
  "description": "Nexrall Code — AI coding assistant for your terminal (headless agent for scripts, CI and automation)",
5
5
  "keywords": [
6
6
  "ai",