nexrall-code 0.5.57 → 0.5.60
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 +256 -86
- package/package.json +11 -11
package/dist/index.js
CHANGED
|
@@ -9982,7 +9982,7 @@ var require_client = __commonJS({
|
|
|
9982
9982
|
}
|
|
9983
9983
|
var MAX_TOTAL_ATTEMPTS = (MAX_RETRIES + 1) * (MAX_RETRIES + 1);
|
|
9984
9984
|
async function streamChat(messages, options, onEvent) {
|
|
9985
|
-
const { model, env: env3, editorContext, nexrallMd, mode, effort, clientType, abortSignal, extraTools, agents, skills, allowRestartAfterRender, canWriteSharedMemory, hasOwnAgentStore } = options;
|
|
9985
|
+
const { model, env: env3, editorContext, nexrallMd, mode, effort, clientType, abortSignal, extraTools, agents, skills, allowRestartAfterRender, canWriteSharedMemory, hasOwnAgentStore, canSpawnSubAgents } = options;
|
|
9986
9986
|
let turnId = (0, crypto_1.randomUUID)();
|
|
9987
9987
|
const controller = new AbortController();
|
|
9988
9988
|
if (abortSignal?.aborted)
|
|
@@ -10023,7 +10023,7 @@ var require_client = __commonJS({
|
|
|
10023
10023
|
{
|
|
10024
10024
|
method: "POST",
|
|
10025
10025
|
headers: authHeaders(),
|
|
10026
|
-
body: JSON.stringify({ messages, model, env: env3, editorContext, nexrallMd, mode, effort, clientType, extraTools, agents, skills, turnId, canWriteSharedMemory, hasOwnAgentStore }),
|
|
10026
|
+
body: JSON.stringify({ messages, model, env: env3, editorContext, nexrallMd, mode, effort, clientType, extraTools, agents, skills, turnId, canWriteSharedMemory, hasOwnAgentStore, canSpawnSubAgents }),
|
|
10027
10027
|
signal: controller.signal
|
|
10028
10028
|
}
|
|
10029
10029
|
];
|
|
@@ -12663,6 +12663,34 @@ ${doc}` : sig || "No type information." };
|
|
|
12663
12663
|
}
|
|
12664
12664
|
});
|
|
12665
12665
|
|
|
12666
|
+
// ../core/dist/util/safeSlice.js
|
|
12667
|
+
var require_safeSlice = __commonJS({
|
|
12668
|
+
"../core/dist/util/safeSlice.js"(exports) {
|
|
12669
|
+
"use strict";
|
|
12670
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12671
|
+
exports.sliceSafeEnd = sliceSafeEnd;
|
|
12672
|
+
exports.sliceSafeStart = sliceSafeStart;
|
|
12673
|
+
function sliceSafeEnd(s2, max) {
|
|
12674
|
+
if (s2.length <= max)
|
|
12675
|
+
return s2;
|
|
12676
|
+
let end = max;
|
|
12677
|
+
const code = s2.charCodeAt(end - 1);
|
|
12678
|
+
if (code >= 55296 && code <= 56319)
|
|
12679
|
+
end--;
|
|
12680
|
+
return s2.slice(0, end);
|
|
12681
|
+
}
|
|
12682
|
+
function sliceSafeStart(s2, from) {
|
|
12683
|
+
if (from <= 0)
|
|
12684
|
+
return s2;
|
|
12685
|
+
let start = from;
|
|
12686
|
+
const code = s2.charCodeAt(start);
|
|
12687
|
+
if (code >= 56320 && code <= 57343)
|
|
12688
|
+
start++;
|
|
12689
|
+
return s2.slice(start);
|
|
12690
|
+
}
|
|
12691
|
+
}
|
|
12692
|
+
});
|
|
12693
|
+
|
|
12666
12694
|
// ../core/dist/tools/executor.js
|
|
12667
12695
|
var require_executor = __commonJS({
|
|
12668
12696
|
"../core/dist/tools/executor.js"(exports) {
|
|
@@ -12731,6 +12759,7 @@ var require_executor = __commonJS({
|
|
|
12731
12759
|
var client_1 = require_client();
|
|
12732
12760
|
var symbols_1 = require_symbols();
|
|
12733
12761
|
var tsLangService_1 = require_tsLangService();
|
|
12762
|
+
var safeSlice_1 = require_safeSlice();
|
|
12734
12763
|
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
12735
12764
|
var MAX_FETCH_BYTES = 200 * 1024;
|
|
12736
12765
|
var MAX_READ_BYTES = 500 * 1024;
|
|
@@ -13024,7 +13053,7 @@ Resolve the conflict (remove <<<<<<< / ======= / >>>>>>> markers and keep the in
|
|
|
13024
13053
|
}
|
|
13025
13054
|
let output = lines.join("\n");
|
|
13026
13055
|
if (output.length > MAX_OUTPUT_CHARS) {
|
|
13027
|
-
output =
|
|
13056
|
+
output = (0, safeSlice_1.sliceSafeEnd)(output, MAX_OUTPUT_CHARS) + `
|
|
13028
13057
|
[Truncated \u2014 ${entries.length} total entries]`;
|
|
13029
13058
|
}
|
|
13030
13059
|
return { output };
|
|
@@ -13496,7 +13525,7 @@ Update these call-sites (or restore the symbol), then run a build/typecheck to c
|
|
|
13496
13525
|
return { output: "No matching files found." };
|
|
13497
13526
|
let out = matches.join("\n");
|
|
13498
13527
|
if (out.length > MAX_OUTPUT_CHARS)
|
|
13499
|
-
out =
|
|
13528
|
+
out = (0, safeSlice_1.sliceSafeEnd)(out, MAX_OUTPUT_CHARS) + "\n[Truncated]";
|
|
13500
13529
|
return { output: out };
|
|
13501
13530
|
} else {
|
|
13502
13531
|
const SEARCH_MAX_BUFFER = 64 * 1024 * 1024;
|
|
@@ -13566,7 +13595,7 @@ ${globalCapMatches(output)}` : "";
|
|
|
13566
13595
|
[Showing first ${GLOBAL_MATCH_CAP} of ${lines.length} matched lines \u2014 narrow the pattern/path for the rest.]`;
|
|
13567
13596
|
}
|
|
13568
13597
|
if (capped.length > MAX_OUTPUT_CHARS) {
|
|
13569
|
-
capped =
|
|
13598
|
+
capped = (0, safeSlice_1.sliceSafeEnd)(capped, MAX_OUTPUT_CHARS);
|
|
13570
13599
|
note = `
|
|
13571
13600
|
[Output truncated at ${MAX_OUTPUT_CHARS / 1024}KB.]`;
|
|
13572
13601
|
}
|
|
@@ -14102,7 +14131,7 @@ ${d}`).join("\n") + xfile + sec
|
|
|
14102
14131
|
return { output: `No files matched pattern: ${pattern}` };
|
|
14103
14132
|
let out = matches.join("\n");
|
|
14104
14133
|
if (out.length > MAX_OUTPUT_CHARS)
|
|
14105
|
-
out =
|
|
14134
|
+
out = (0, safeSlice_1.sliceSafeEnd)(out, MAX_OUTPUT_CHARS) + "\n[Truncated]";
|
|
14106
14135
|
return { output: `${matches.length} file(s) matched "${pattern}":
|
|
14107
14136
|
${out}` };
|
|
14108
14137
|
} catch (err) {
|
|
@@ -14158,7 +14187,7 @@ ${lines.join("\n")}`;
|
|
|
14158
14187
|
switch (out.output_type) {
|
|
14159
14188
|
case "stream": {
|
|
14160
14189
|
const txt = nbJoin(out.text ?? "");
|
|
14161
|
-
lines.push(`[${out.name === "stderr" ? "stderr" : "stdout"}] ${
|
|
14190
|
+
lines.push(`[${out.name === "stderr" ? "stderr" : "stdout"}] ${(0, safeSlice_1.sliceSafeEnd)(txt, 3e3)}${txt.length > 3e3 ? "\n[truncated]" : ""}`);
|
|
14162
14191
|
break;
|
|
14163
14192
|
}
|
|
14164
14193
|
case "execute_result":
|
|
@@ -14168,9 +14197,9 @@ ${lines.join("\n")}`;
|
|
|
14168
14197
|
const html = d["text/html"] ? nbJoin(d["text/html"]) : null;
|
|
14169
14198
|
const hasImg = "image/png" in d || "image/jpeg" in d || "image/svg+xml" in d;
|
|
14170
14199
|
if (plain)
|
|
14171
|
-
lines.push(
|
|
14200
|
+
lines.push((0, safeSlice_1.sliceSafeEnd)(plain, 2e3) + (plain.length > 2e3 ? "\n[truncated]" : ""));
|
|
14172
14201
|
else if (html)
|
|
14173
|
-
lines.push(stripHtml(html)
|
|
14202
|
+
lines.push((0, safeSlice_1.sliceSafeEnd)(stripHtml(html), 1e3));
|
|
14174
14203
|
if (hasImg)
|
|
14175
14204
|
lines.push("[image output \u2014 not shown in text mode]");
|
|
14176
14205
|
break;
|
|
@@ -14179,7 +14208,7 @@ ${lines.join("\n")}`;
|
|
|
14179
14208
|
lines.push(`[error] ${out.ename ?? "Error"}: ${out.evalue ?? ""}`);
|
|
14180
14209
|
if (out.traceback) {
|
|
14181
14210
|
const clean = out.traceback.map((l) => l.replace(/\x1b\[[0-9;]*[mGKH]/g, "")).join("\n");
|
|
14182
|
-
lines.push(
|
|
14211
|
+
lines.push((0, safeSlice_1.sliceSafeEnd)(clean, 1500) + (clean.length > 1500 ? "\n[truncated]" : ""));
|
|
14183
14212
|
}
|
|
14184
14213
|
break;
|
|
14185
14214
|
}
|
|
@@ -14222,7 +14251,7 @@ ${lines.join("\n")}`;
|
|
|
14222
14251
|
});
|
|
14223
14252
|
let output = lines.join("\n");
|
|
14224
14253
|
if (output.length > MAX_OUTPUT_CHARS) {
|
|
14225
|
-
output =
|
|
14254
|
+
output = (0, safeSlice_1.sliceSafeEnd)(output, MAX_OUTPUT_CHARS) + "\n\n[Notebook output truncated at 100KB]";
|
|
14226
14255
|
}
|
|
14227
14256
|
return { output };
|
|
14228
14257
|
} catch (err) {
|
|
@@ -14733,9 +14762,17 @@ var require_agentTypes = __commonJS({
|
|
|
14733
14762
|
//
|
|
14734
14763
|
// `tools` is deliberately UNDEFINED, which means "no allowlist" — full access,
|
|
14735
14764
|
// inheriting whatever the session permits. That is the same power an unnamed
|
|
14736
|
-
// sub-task always had; naming it changes only who can see and deny it.
|
|
14737
|
-
//
|
|
14738
|
-
//
|
|
14765
|
+
// sub-task always had; naming it changes only who can see and deny it.
|
|
14766
|
+
//
|
|
14767
|
+
// It also makes this the ONLY builtin that can nest, since every specialist omits
|
|
14768
|
+
// `task` on purpose. So the tree this enables is up to `maxSubagentDepth` generations
|
|
14769
|
+
// of unrestricted agents — accepted deliberately, because the alternative (a catch-all
|
|
14770
|
+
// that cannot delegate) removes the one agent suited to orchestration.
|
|
14771
|
+
//
|
|
14772
|
+
// The safety properties that bound it: plan mode is inherited, the user's permission
|
|
14773
|
+
// gate runs on every call, a child's allowlist is INTERSECTED with its parent's so a
|
|
14774
|
+
// restricted ancestor cannot be escaped through this agent, `test_files_only` is
|
|
14775
|
+
// likewise sticky, and both the depth ceiling and the session budget still apply.
|
|
14739
14776
|
name: "general-purpose",
|
|
14740
14777
|
description: "General-purpose worker for a multi-step task that needs BOTH exploration and changes (edit files, run commands) and that no specialist above fits. Inherits the session model and full tool access, so prefer a narrower agent when one matches.",
|
|
14741
14778
|
prompt: "You are a general-purpose engineering sub-agent. Work the task end to end: explore what you need, make the changes, and verify them with the project's own build/test commands.\n\nRules:\n- Mirror existing conventions; make the smallest correct change.\n- Verify before you claim success. If you could not verify, say so explicitly.\n- Your FINAL MESSAGE is the only thing that reaches the main agent: state what you changed (with file paths), what you ran and its outcome, and anything you deliberately left undone.",
|
|
@@ -15061,6 +15098,13 @@ var require_agentTypes = __commonJS({
|
|
|
15061
15098
|
message: `lists unknown tool name(s): ${unknown.join(", ")}. An allowlist only grants, so these silently do nothing and the agent cannot use them. Tool names are lower_snake_case (read_file, search_files, glob, bash).`
|
|
15062
15099
|
});
|
|
15063
15100
|
}
|
|
15101
|
+
if ((tools ?? []).length === 1 && tools?.[0] === "task") {
|
|
15102
|
+
warnings.push({
|
|
15103
|
+
file: full,
|
|
15104
|
+
agent: name,
|
|
15105
|
+
message: "lists `task` as its ONLY tool, so it can delegate but cannot read, write or run anything itself \u2014 it has no way to do or verify work. Add the tools it needs, or drop the `tools:` line to inherit its parent's."
|
|
15106
|
+
});
|
|
15107
|
+
}
|
|
15064
15108
|
const strayKeys = Object.keys(meta).filter((k) => !KNOWN_META_KEYS.has(k));
|
|
15065
15109
|
if (strayKeys.length) {
|
|
15066
15110
|
warnings.push({
|
|
@@ -15697,10 +15741,12 @@ var require_agentRegistry = __commonJS({
|
|
|
15697
15741
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15698
15742
|
exports._limits = void 0;
|
|
15699
15743
|
exports.rememberAgent = rememberAgent;
|
|
15744
|
+
exports.canResume = canResume;
|
|
15700
15745
|
exports.updateAgent = updateAgent;
|
|
15701
15746
|
exports.getAgent = getAgent;
|
|
15702
15747
|
exports.listAgents = listAgents;
|
|
15703
15748
|
exports._resetAgentRegistry = _resetAgentRegistry;
|
|
15749
|
+
var node_crypto_1 = __require("node:crypto");
|
|
15704
15750
|
var MAX_AGENTS = 20;
|
|
15705
15751
|
var MAX_TOTAL_BYTES = 8 * 1024 * 1024;
|
|
15706
15752
|
var _agents = /* @__PURE__ */ new Map();
|
|
@@ -15733,12 +15779,13 @@ var require_agentRegistry = __commonJS({
|
|
|
15733
15779
|
return MAX_TOTAL_BYTES;
|
|
15734
15780
|
}
|
|
15735
15781
|
}
|
|
15736
|
-
function rememberAgent(agentName, description, messages) {
|
|
15737
|
-
const id = `agent_${++_counter}`;
|
|
15782
|
+
function rememberAgent(agentName, description, messages, ownerScope = "root") {
|
|
15783
|
+
const id = `agent_${++_counter}_${(0, node_crypto_1.randomUUID)().slice(0, 8)}`;
|
|
15738
15784
|
const now = Date.now();
|
|
15739
15785
|
_agents.set(id, {
|
|
15740
15786
|
id,
|
|
15741
15787
|
agentName,
|
|
15788
|
+
ownerScope,
|
|
15742
15789
|
description,
|
|
15743
15790
|
messages,
|
|
15744
15791
|
createdAt: now,
|
|
@@ -15749,10 +15796,15 @@ var require_agentRegistry = __commonJS({
|
|
|
15749
15796
|
evictUntilWithinLimits();
|
|
15750
15797
|
return id;
|
|
15751
15798
|
}
|
|
15752
|
-
function
|
|
15799
|
+
function canResume(stored, scope) {
|
|
15800
|
+
return stored.ownerScope === scope || scope === "root";
|
|
15801
|
+
}
|
|
15802
|
+
function updateAgent(id, messages, scope = "root") {
|
|
15753
15803
|
const existing = _agents.get(id);
|
|
15754
15804
|
if (!existing)
|
|
15755
15805
|
return;
|
|
15806
|
+
if (!canResume(existing, scope))
|
|
15807
|
+
return;
|
|
15756
15808
|
existing.messages = messages;
|
|
15757
15809
|
existing.updatedAt = Date.now();
|
|
15758
15810
|
existing.seq = ++_seq;
|
|
@@ -15961,8 +16013,15 @@ var require_loop = __commonJS({
|
|
|
15961
16013
|
exports.resolveMaxIterations = resolveMaxIterations;
|
|
15962
16014
|
exports.lockPathsFor = lockPathsFor;
|
|
15963
16015
|
exports.resolveMaxConcurrentSubtasks = resolveMaxConcurrentSubtasks;
|
|
16016
|
+
exports.resolveMaxSubagentsPerSession = resolveMaxSubagentsPerSession;
|
|
15964
16017
|
exports.createLimiter = createLimiter;
|
|
15965
16018
|
exports._resetSubTaskLimiter = _resetSubTaskLimiter;
|
|
16019
|
+
exports.resetSessionSubAgentBudget = resetSessionSubAgentBudget2;
|
|
16020
|
+
exports._sessionSubAgentCount = _sessionSubAgentCount;
|
|
16021
|
+
exports.resolveMaxSubagentDepth = resolveMaxSubagentDepth;
|
|
16022
|
+
exports.noSpawnReason = noSpawnReason;
|
|
16023
|
+
exports.intersectAllowlists = intersectAllowlists;
|
|
16024
|
+
exports.canSpawnSubAgents = canSpawnSubAgents;
|
|
15966
16025
|
exports.resolveSubtaskTimeoutMs = resolveSubtaskTimeoutMs;
|
|
15967
16026
|
exports.extractSubTaskText = extractSubTaskText;
|
|
15968
16027
|
exports.capSubTaskText = capSubTaskText;
|
|
@@ -16000,6 +16059,7 @@ var require_loop = __commonJS({
|
|
|
16000
16059
|
var flaky_1 = require_flaky();
|
|
16001
16060
|
var claimEvidence_1 = require_claimEvidence();
|
|
16002
16061
|
var memory_1 = require_memory();
|
|
16062
|
+
var safeSlice_1 = require_safeSlice();
|
|
16003
16063
|
var fs9 = __importStar(__require("fs"));
|
|
16004
16064
|
var path6 = __importStar(__require("path"));
|
|
16005
16065
|
var child_process_1 = __require("child_process");
|
|
@@ -16234,7 +16294,7 @@ ${ctx.repeatError}
|
|
|
16234
16294
|
}
|
|
16235
16295
|
var DEFAULT_MAX_CONCURRENT_SUBTASKS = 4;
|
|
16236
16296
|
function resolveMaxConcurrentSubtasks(settingsRaw = {}) {
|
|
16237
|
-
const clamp = (n) => Math.min(Math.floor(n), 16);
|
|
16297
|
+
const clamp = (n) => Math.max(1, Math.min(Math.floor(n), 16));
|
|
16238
16298
|
const fromEnv = Number(process.env.NEXRALL_MAX_CONCURRENT_SUBTASKS);
|
|
16239
16299
|
if (Number.isFinite(fromEnv) && fromEnv > 0)
|
|
16240
16300
|
return clamp(fromEnv);
|
|
@@ -16243,6 +16303,17 @@ ${ctx.repeatError}
|
|
|
16243
16303
|
return clamp(fromSettings);
|
|
16244
16304
|
return DEFAULT_MAX_CONCURRENT_SUBTASKS;
|
|
16245
16305
|
}
|
|
16306
|
+
var DEFAULT_MAX_SUBAGENTS_PER_SESSION = 100;
|
|
16307
|
+
function resolveMaxSubagentsPerSession(settingsRaw = {}) {
|
|
16308
|
+
const floor = (n) => Math.max(1, Math.min(Math.floor(n), 1e4));
|
|
16309
|
+
const fromEnv = Number(process.env.NEXRALL_MAX_SUBAGENTS_PER_SESSION);
|
|
16310
|
+
if (Number.isFinite(fromEnv) && fromEnv > 0)
|
|
16311
|
+
return floor(fromEnv);
|
|
16312
|
+
const fromSettings = Number(settingsRaw.maxSubagentsPerSession);
|
|
16313
|
+
if (Number.isFinite(fromSettings) && fromSettings > 0)
|
|
16314
|
+
return floor(fromSettings);
|
|
16315
|
+
return DEFAULT_MAX_SUBAGENTS_PER_SESSION;
|
|
16316
|
+
}
|
|
16246
16317
|
function createLimiter(max) {
|
|
16247
16318
|
let active = 0;
|
|
16248
16319
|
const queue = [];
|
|
@@ -16261,19 +16332,61 @@ ${ctx.repeatError}
|
|
|
16261
16332
|
}
|
|
16262
16333
|
};
|
|
16263
16334
|
}
|
|
16264
|
-
var
|
|
16335
|
+
var _subTaskLimiters = /* @__PURE__ */ new Map();
|
|
16336
|
+
var _subTaskLimitMaxByDepth = /* @__PURE__ */ new Map();
|
|
16265
16337
|
var _subTaskLimitMax = 0;
|
|
16266
|
-
var
|
|
16267
|
-
function subTaskLimiter(workDir) {
|
|
16268
|
-
if (!
|
|
16338
|
+
var _inFlightByDepth = /* @__PURE__ */ new Map();
|
|
16339
|
+
function subTaskLimiter(depth, workDir) {
|
|
16340
|
+
if (!_subTaskLimitMax) {
|
|
16269
16341
|
_subTaskLimitMax = resolveMaxConcurrentSubtasks(workDir ? (0, rules_1.loadSettings)(workDir).raw : {});
|
|
16270
|
-
_subTaskLimitInstance = createLimiter(_subTaskLimitMax);
|
|
16271
16342
|
}
|
|
16272
|
-
|
|
16343
|
+
let run = _subTaskLimiters.get(depth);
|
|
16344
|
+
let max = _subTaskLimitMaxByDepth.get(depth) ?? 0;
|
|
16345
|
+
if (!run) {
|
|
16346
|
+
max = Math.max(1, Math.ceil(_subTaskLimitMax / 2 ** Math.max(0, depth - 1)));
|
|
16347
|
+
run = createLimiter(max);
|
|
16348
|
+
_subTaskLimiters.set(depth, run);
|
|
16349
|
+
_subTaskLimitMaxByDepth.set(depth, max);
|
|
16350
|
+
}
|
|
16351
|
+
return { run, max };
|
|
16273
16352
|
}
|
|
16274
16353
|
function _resetSubTaskLimiter() {
|
|
16275
|
-
|
|
16354
|
+
_subTaskLimiters.clear();
|
|
16355
|
+
_subTaskLimitMaxByDepth.clear();
|
|
16356
|
+
_inFlightByDepth.clear();
|
|
16276
16357
|
_subTaskLimitMax = 0;
|
|
16358
|
+
_subAgentsThisSession = 0;
|
|
16359
|
+
_sessionCapMax = 0;
|
|
16360
|
+
_sessionCapNotified = false;
|
|
16361
|
+
}
|
|
16362
|
+
var _subAgentsThisSession = 0;
|
|
16363
|
+
var _sessionCapMax = 0;
|
|
16364
|
+
var _sessionCapNotified = false;
|
|
16365
|
+
function resetSessionSubAgentBudget2() {
|
|
16366
|
+
_subAgentsThisSession = 0;
|
|
16367
|
+
_sessionCapMax = 0;
|
|
16368
|
+
_sessionCapNotified = false;
|
|
16369
|
+
}
|
|
16370
|
+
function claimSessionSubAgentSlot(workDir, notify) {
|
|
16371
|
+
if (!_sessionCapMax) {
|
|
16372
|
+
_sessionCapMax = resolveMaxSubagentsPerSession(workDir ? (0, rules_1.loadSettings)(workDir).raw : {});
|
|
16373
|
+
}
|
|
16374
|
+
if (_subAgentsThisSession >= _sessionCapMax) {
|
|
16375
|
+
if (!_sessionCapNotified) {
|
|
16376
|
+
_sessionCapNotified = true;
|
|
16377
|
+
notify?.(`\u26A0\uFE0F Sub-agent budget reached (${_sessionCapMax} this session) \u2014 further delegation is blocked and the agent will continue without it. Raise "maxSubagentsPerSession" in .nexrall/settings.json if this was legitimate work.`);
|
|
16378
|
+
}
|
|
16379
|
+
return `Sub-agent budget for this session is exhausted (${_sessionCapMax} started). This is a runaway-delegation guard, not a per-task limit: do the remaining work directly, and say in your final message that you hit the delegation cap.`;
|
|
16380
|
+
}
|
|
16381
|
+
_subAgentsThisSession++;
|
|
16382
|
+
return null;
|
|
16383
|
+
}
|
|
16384
|
+
function refundSessionSubAgentSlot() {
|
|
16385
|
+
if (_subAgentsThisSession > 0)
|
|
16386
|
+
_subAgentsThisSession--;
|
|
16387
|
+
}
|
|
16388
|
+
function _sessionSubAgentCount() {
|
|
16389
|
+
return _subAgentsThisSession;
|
|
16277
16390
|
}
|
|
16278
16391
|
function humanDescription(name, input) {
|
|
16279
16392
|
switch (name) {
|
|
@@ -16356,7 +16469,36 @@ ${ctx.repeatError}
|
|
|
16356
16469
|
return `Use tool: ${name}`;
|
|
16357
16470
|
}
|
|
16358
16471
|
}
|
|
16359
|
-
var
|
|
16472
|
+
var DEFAULT_MAX_TASK_DEPTH = 3;
|
|
16473
|
+
var HARD_MAX_TASK_DEPTH = 5;
|
|
16474
|
+
function resolveMaxSubagentDepth(settingsRaw = {}) {
|
|
16475
|
+
const clamp = (n) => Math.max(1, Math.min(Math.floor(n), HARD_MAX_TASK_DEPTH));
|
|
16476
|
+
const fromEnv = Number(process.env.NEXRALL_MAX_SUBAGENT_DEPTH);
|
|
16477
|
+
if (Number.isFinite(fromEnv) && fromEnv > 0)
|
|
16478
|
+
return clamp(fromEnv);
|
|
16479
|
+
const fromSettings = Number(settingsRaw.maxSubagentDepth);
|
|
16480
|
+
if (Number.isFinite(fromSettings) && fromSettings > 0)
|
|
16481
|
+
return clamp(fromSettings);
|
|
16482
|
+
return DEFAULT_MAX_TASK_DEPTH;
|
|
16483
|
+
}
|
|
16484
|
+
function noSpawnReason(kind, limit) {
|
|
16485
|
+
if (kind === "denied") {
|
|
16486
|
+
return "This sub-agent's definition does not grant `task`, so it may not delegate. That is a deliberate restriction on this agent type \u2014 do not ask for approval and do not look for a way around it. Do the work with the tools you have, or report back what is missing.";
|
|
16487
|
+
}
|
|
16488
|
+
return `Maximum sub-agent nesting depth (${limit ?? DEFAULT_MAX_TASK_DEPTH}) reached, so this run is a leaf and cannot delegate further. Depth is a budget, not a bug: finish this work yourself, or report back so a shallower frame can decide. (The ceiling is "maxSubagentDepth" in .nexrall/settings.json, but raising it mid-task will not help you \u2014 it applies from the next session.)`;
|
|
16489
|
+
}
|
|
16490
|
+
function intersectAllowlists(own, parent) {
|
|
16491
|
+
if (own && parent)
|
|
16492
|
+
return new Set([...own].filter((t2) => parent.has(t2)));
|
|
16493
|
+
if (own)
|
|
16494
|
+
return own;
|
|
16495
|
+
return parent ? new Set(parent) : null;
|
|
16496
|
+
}
|
|
16497
|
+
function canSpawnSubAgents(depth, allowedTools, limit = DEFAULT_MAX_TASK_DEPTH) {
|
|
16498
|
+
if (depth >= limit)
|
|
16499
|
+
return false;
|
|
16500
|
+
return allowedTools ? allowedTools.has("task") : true;
|
|
16501
|
+
}
|
|
16360
16502
|
var _subTaskCounter = 0;
|
|
16361
16503
|
var DEFAULT_SUBTASK_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
16362
16504
|
function resolveSubtaskTimeoutMs(settingsRaw) {
|
|
@@ -16377,24 +16519,6 @@ ${ctx.repeatError}
|
|
|
16377
16519
|
}
|
|
16378
16520
|
};
|
|
16379
16521
|
exports.ToolNotAllowedError = ToolNotAllowedError;
|
|
16380
|
-
function sliceSafeEnd(s2, max) {
|
|
16381
|
-
if (s2.length <= max)
|
|
16382
|
-
return s2;
|
|
16383
|
-
let end = max;
|
|
16384
|
-
const code = s2.charCodeAt(end - 1);
|
|
16385
|
-
if (code >= 55296 && code <= 56319)
|
|
16386
|
-
end--;
|
|
16387
|
-
return s2.slice(0, end);
|
|
16388
|
-
}
|
|
16389
|
-
function sliceSafeStart(s2, from) {
|
|
16390
|
-
if (from <= 0)
|
|
16391
|
-
return s2;
|
|
16392
|
-
let start = from;
|
|
16393
|
-
const code = s2.charCodeAt(start);
|
|
16394
|
-
if (code >= 56320 && code <= 57343)
|
|
16395
|
-
start++;
|
|
16396
|
-
return s2.slice(start);
|
|
16397
|
-
}
|
|
16398
16522
|
function extractSubTaskText(messages, preferLast = true) {
|
|
16399
16523
|
const assistants = messages.filter((m2) => m2.role === "assistant");
|
|
16400
16524
|
const textOf = (m2) => (m2?.content ?? []).filter((b) => b.type === "text" && typeof b.text === "string").map((b) => b.text).join("").trim();
|
|
@@ -16405,8 +16529,8 @@ ${ctx.repeatError}
|
|
|
16405
16529
|
function capSubTaskText(text, max = SUBTASK_MAX) {
|
|
16406
16530
|
if (text.length <= max)
|
|
16407
16531
|
return text;
|
|
16408
|
-
const head = sliceSafeEnd(text, Math.floor(max * 0.6));
|
|
16409
|
-
const tail = sliceSafeStart(text, text.length - Math.floor(max * 0.4));
|
|
16532
|
+
const head = (0, safeSlice_1.sliceSafeEnd)(text, Math.floor(max * 0.6));
|
|
16533
|
+
const tail = (0, safeSlice_1.sliceSafeStart)(text, text.length - Math.floor(max * 0.4));
|
|
16410
16534
|
return `${head}
|
|
16411
16535
|
|
|
16412
16536
|
[\u2026 sub-task output truncated (${text.length} chars) \u2014 kept the beginning and end \u2026]
|
|
@@ -16462,7 +16586,7 @@ ${recentFindings}` : header;
|
|
|
16462
16586
|
if (!text)
|
|
16463
16587
|
continue;
|
|
16464
16588
|
const name = nameById.get(String(b.tool_use_id ?? "")) ?? "tool";
|
|
16465
|
-
const body = text.length > maxChars ? `${sliceSafeEnd(text, maxChars)}
|
|
16589
|
+
const body = text.length > maxChars ? `${(0, safeSlice_1.sliceSafeEnd)(text, maxChars)}
|
|
16466
16590
|
\u2026 [truncated]` : text;
|
|
16467
16591
|
out.push(`\u2022 ${name}:
|
|
16468
16592
|
${body}`);
|
|
@@ -16479,29 +16603,35 @@ ${body}`);
|
|
|
16479
16603
|
}
|
|
16480
16604
|
return "";
|
|
16481
16605
|
}
|
|
16482
|
-
async function runSubTask(input, options, agentTypes) {
|
|
16606
|
+
async function runSubTask(input, options, agentTypes, started) {
|
|
16483
16607
|
const prompt2 = typeof input.prompt === "string" ? input.prompt.trim() : "";
|
|
16484
16608
|
if (!prompt2)
|
|
16485
16609
|
return { error: "task tool requires a non-empty prompt" };
|
|
16610
|
+
const agentScope = options._agentScope ?? "root";
|
|
16486
16611
|
const depth = options._depth ?? 0;
|
|
16487
|
-
|
|
16488
|
-
|
|
16612
|
+
const depthLimit = resolveMaxSubagentDepth(options.workDir ? (0, rules_1.loadSettings)(options.workDir).raw : {});
|
|
16613
|
+
if (depth >= depthLimit) {
|
|
16614
|
+
return { error: noSpawnReason("depth", depthLimit) };
|
|
16489
16615
|
}
|
|
16490
16616
|
const resumeId = typeof input.resume_agent_id === "string" ? input.resume_agent_id.trim() : "";
|
|
16491
16617
|
const resumed = resumeId ? (0, agentRegistry_1.getAgent)(resumeId) : void 0;
|
|
16618
|
+
if (resumed && !(0, agentRegistry_1.canResume)(resumed, agentScope)) {
|
|
16619
|
+
return {
|
|
16620
|
+
error: `No resumable sub-agent with id "${resumeId}" is available to this run. Start a fresh sub-task with a self-contained prompt instead.`
|
|
16621
|
+
};
|
|
16622
|
+
}
|
|
16492
16623
|
if (resumeId && !resumed) {
|
|
16493
16624
|
return {
|
|
16494
16625
|
error: `No resumable sub-agent with id "${resumeId}". Ids live only for the current session and the oldest are dropped when too many accumulate, so this one has expired or never existed. Start a fresh sub-task with a self-contained prompt instead.`
|
|
16495
16626
|
};
|
|
16496
16627
|
}
|
|
16497
16628
|
const requestedType = resumed ? resumed.agentName ?? "" : typeof input.subagent_type === "string" ? input.subagent_type : "";
|
|
16498
|
-
|
|
16499
|
-
|
|
16500
|
-
|
|
16501
|
-
|
|
16502
|
-
|
|
16503
|
-
|
|
16504
|
-
}
|
|
16629
|
+
const denyKey = requestedType || "general-purpose";
|
|
16630
|
+
const decision = (0, rules_1.evaluatePermission)((0, rules_1.loadSettings)(options.workDir).permissions, "task", { subagent_type: denyKey }, options.workDir);
|
|
16631
|
+
if (decision === "deny") {
|
|
16632
|
+
return {
|
|
16633
|
+
error: `The sub-agent "${denyKey}" is disabled by a permission rule in this project (permissions.deny in settings.json). This is a deliberate policy choice, not a missing file \u2014 do not create it and do not retry. Do the work yourself, or use a different sub-agent.`
|
|
16634
|
+
};
|
|
16505
16635
|
}
|
|
16506
16636
|
let agent = (0, agentTypes_1.findAgentType)(agentTypes, requestedType);
|
|
16507
16637
|
let knownTypes = agentTypes;
|
|
@@ -16529,18 +16659,31 @@ ${agentMemoryNotes}` : "") + (inheritedMd ? `
|
|
|
16529
16659
|
---
|
|
16530
16660
|
|
|
16531
16661
|
${inheritedMd}` : "") : options.nexrallMd;
|
|
16532
|
-
const
|
|
16662
|
+
const testFilesOnly = !!agent?.testFilesOnly || !!options._testFilesOnly;
|
|
16663
|
+
const allowed = intersectAllowlists(agent?.tools ? new Set(agent.tools) : null, options._allowedTools);
|
|
16533
16664
|
if (allowed && memoryScope)
|
|
16534
16665
|
allowed.add(exports.AGENT_MEMORY_TOOL);
|
|
16535
16666
|
const gatedPermission = async (req) => {
|
|
16536
16667
|
if (req.tool === exports.AGENT_MEMORY_TOOL && !(agent && memoryScope)) {
|
|
16537
16668
|
throw new ToolNotAllowedError(`\`${exports.AGENT_MEMORY_TOOL}\` is only available to a sub-agent whose definition declares a \`memory:\` scope (project, user or local). Report anything worth remembering in your final message instead \u2014 the main agent decides what to persist.`);
|
|
16538
16669
|
}
|
|
16670
|
+
if (req.tool === "task" && !canSpawnSubAgents(depth + 1, allowed ?? void 0, depthLimit)) {
|
|
16671
|
+
throw new ToolNotAllowedError(allowed && !allowed.has("task") ? noSpawnReason("denied") : noSpawnReason("depth", depthLimit));
|
|
16672
|
+
}
|
|
16539
16673
|
if (allowed && !allowed.has(req.tool)) {
|
|
16540
|
-
throw new ToolNotAllowedError(
|
|
16674
|
+
throw new ToolNotAllowedError(
|
|
16675
|
+
// `agent?.name`, NOT `agent!.name`. The non-null assertion held only while `allowed`
|
|
16676
|
+
// was derived solely from `agent?.tools` (non-null allowlist ⇒ named agent). The
|
|
16677
|
+
// parent-intersection broke that invariant: a RESTRICTED parent dispatching `task`
|
|
16678
|
+
// with no subagent_type yields a non-null inherited allowlist with `agent`
|
|
16679
|
+
// undefined, and this line then threw a TypeError instead of ToolNotAllowedError —
|
|
16680
|
+
// which the dispatch site does not recognise, so it laundered the refusal into the
|
|
16681
|
+
// generic "Permission denied by user" this very message exists to avoid.
|
|
16682
|
+
`The "${agent?.name ?? "general-purpose"}" sub-agent is not allowed to use \`${req.tool}\` \u2014 it is not in that agent's tool allowlist. This is a restriction of the agent definition, NOT a user decision: do not ask for approval, use one of the tools you do have, or report back that the task needs a different agent.`
|
|
16683
|
+
);
|
|
16541
16684
|
}
|
|
16542
|
-
if (
|
|
16543
|
-
throw new ToolNotAllowedError(`The "${agent
|
|
16685
|
+
if (testFilesOnly && !allowsTestOnlyWrite(req.tool, req.input)) {
|
|
16686
|
+
throw new ToolNotAllowedError(`The "${agent?.name ?? "general-purpose"}" sub-agent may only write to TEST files, so \`${req.tool}\` was refused for this path. Do not try to work around it: if production code must change, say so in your report instead.`);
|
|
16544
16687
|
}
|
|
16545
16688
|
return options.requestPermission(req);
|
|
16546
16689
|
};
|
|
@@ -16563,6 +16706,8 @@ ${inheritedMd}` : "") : options.nexrallMd;
|
|
|
16563
16706
|
subAbort.aborted = true;
|
|
16564
16707
|
}, 250);
|
|
16565
16708
|
try {
|
|
16709
|
+
if (started)
|
|
16710
|
+
started.value = true;
|
|
16566
16711
|
const result = await runAgentLoop2(subMessages, {
|
|
16567
16712
|
...options,
|
|
16568
16713
|
_depth: depth + 1,
|
|
@@ -16580,15 +16725,21 @@ ${inheritedMd}` : "") : options.nexrallMd;
|
|
|
16580
16725
|
// `tools:` line inherited the parent's allowlist, making the prompt's capability
|
|
16581
16726
|
// claim disagree with its real one.
|
|
16582
16727
|
//
|
|
16583
|
-
//
|
|
16584
|
-
//
|
|
16585
|
-
//
|
|
16586
|
-
//
|
|
16587
|
-
//
|
|
16728
|
+
// This is now LIVE, not latent: nesting is enabled by default, so a grandchild really
|
|
16729
|
+
// can be spawned by an agent that has a memory binding. The explicit `undefined` is
|
|
16730
|
+
// what stops it inheriting that binding and appending to its grandparent's private
|
|
16731
|
+
// notes — a silent cross-agent write rather than a visible error. Note the allowlist
|
|
16732
|
+
// takes the opposite direction on purpose (inherited, because it RESTRICTS); identity
|
|
16733
|
+
// must not be inherited, capability must.
|
|
16588
16734
|
_agentMemory: agent && memoryScope ? { agentName: agent.name, scope: memoryScope } : void 0,
|
|
16589
16735
|
// The same set `gatedPermission` enforces above, so prompt and permission agree
|
|
16590
16736
|
// by construction instead of by two people remembering to update both.
|
|
16591
16737
|
_allowedTools: allowed ?? void 0,
|
|
16738
|
+
// Propagated so a grandchild inherits it too — see _testFilesOnly. Assigned
|
|
16739
|
+
// unconditionally (not by conditional spread) for the same reason as _agentMemory
|
|
16740
|
+
// above: a conditional spread leaves the parent's value in place instead of clearing
|
|
16741
|
+
// it, and here that direction is at least safe, whereas forgetting to propagate is not.
|
|
16742
|
+
_testFilesOnly: testFilesOnly,
|
|
16592
16743
|
editorContext: null,
|
|
16593
16744
|
// fresh isolated context for sub-agent
|
|
16594
16745
|
model: agent?.model ?? options.model,
|
|
@@ -16654,7 +16805,7 @@ ${inheritedMd}` : "") : options.nexrallMd;
|
|
|
16654
16805
|
const mins = Math.round(subtaskTimeoutMs / 6e4);
|
|
16655
16806
|
const partial = capSubTaskText(extractSubTaskText(result, false));
|
|
16656
16807
|
const progress = summariseSubTaskProgress(result);
|
|
16657
|
-
const partialId = (0, agentRegistry_1.rememberAgent)(agent?.name ?? null, typeof input.description === "string" && input.description.trim() || prompt2.slice(0, 80), result);
|
|
16808
|
+
const partialId = (0, agentRegistry_1.rememberAgent)(agent?.name ?? null, typeof input.description === "string" && input.description.trim() || prompt2.slice(0, 80), result, agentScope);
|
|
16658
16809
|
const sections = [
|
|
16659
16810
|
`Sub-task STOPPED after ${mins} minutes with NO PROGRESS (it was not making tool calls or producing output) \u2014 treat everything below as PARTIAL, unverified work, not a finished answer.`,
|
|
16660
16811
|
progress,
|
|
@@ -16666,7 +16817,7 @@ ${partial}` : "",
|
|
|
16666
16817
|
return { error: sections.join("\n\n") };
|
|
16667
16818
|
}
|
|
16668
16819
|
const text = capSubTaskText(extractSubTaskText(result, true));
|
|
16669
|
-
const agentId = resumed ? ((0, agentRegistry_1.updateAgent)(resumed.id, result), resumed.id) : (0, agentRegistry_1.rememberAgent)(agent?.name ?? null, typeof input.description === "string" && input.description.trim() || prompt2.slice(0, 80), result);
|
|
16820
|
+
const agentId = resumed ? ((0, agentRegistry_1.updateAgent)(resumed.id, result, agentScope), resumed.id) : (0, agentRegistry_1.rememberAgent)(agent?.name ?? null, typeof input.description === "string" && input.description.trim() || prompt2.slice(0, 80), result, agentScope);
|
|
16670
16821
|
const body = text || "(sub-task completed with no text output)";
|
|
16671
16822
|
return {
|
|
16672
16823
|
output: `${body}
|
|
@@ -16771,11 +16922,11 @@ ${partial}` : "",
|
|
|
16771
16922
|
for (const m2 of messages) {
|
|
16772
16923
|
for (const b of m2.content) {
|
|
16773
16924
|
if (b.type === "text" && b.text) {
|
|
16774
|
-
parts.push(`${m2.role.toUpperCase()}: ${b.text
|
|
16925
|
+
parts.push(`${m2.role.toUpperCase()}: ${(0, safeSlice_1.sliceSafeEnd)(b.text, 2e3)}`);
|
|
16775
16926
|
} else if (b.type === "tool_use") {
|
|
16776
|
-
parts.push(`${m2.role.toUpperCase()} [tool: ${b.name}]: ${JSON.stringify(b.input ?? {})
|
|
16927
|
+
parts.push(`${m2.role.toUpperCase()} [tool: ${b.name}]: ${(0, safeSlice_1.sliceSafeEnd)(JSON.stringify(b.input ?? {}), 400)}`);
|
|
16777
16928
|
} else if (b.type === "tool_result") {
|
|
16778
|
-
parts.push(`TOOL RESULT: ${String(b.content ?? "")
|
|
16929
|
+
parts.push(`TOOL RESULT: ${(0, safeSlice_1.sliceSafeEnd)(String(b.content ?? ""), 600)}`);
|
|
16779
16930
|
}
|
|
16780
16931
|
}
|
|
16781
16932
|
}
|
|
@@ -16784,8 +16935,8 @@ ${partial}` : "",
|
|
|
16784
16935
|
return full;
|
|
16785
16936
|
const headBudget = Math.floor(MAX_TRANSCRIPT_CHARS * 0.4);
|
|
16786
16937
|
const tailBudget = MAX_TRANSCRIPT_CHARS - headBudget;
|
|
16787
|
-
const head =
|
|
16788
|
-
const tail =
|
|
16938
|
+
const head = (0, safeSlice_1.sliceSafeEnd)(full, headBudget);
|
|
16939
|
+
const tail = (0, safeSlice_1.sliceSafeStart)(full, full.length - tailBudget);
|
|
16789
16940
|
const dropped = full.length - head.length - tail.length;
|
|
16790
16941
|
return `${head}
|
|
16791
16942
|
|
|
@@ -17070,7 +17221,9 @@ Continue the work from here.` }] });
|
|
|
17070
17221
|
const agentScope = options._agentScope ?? "root";
|
|
17071
17222
|
const settings = (0, rules_1.loadSettings)(options.workDir);
|
|
17072
17223
|
const agentTypes = (0, agentTypes_1.loadAgentTypes)(options.workDir).filter((t2) => (0, rules_1.evaluatePermission)(settings.permissions, "task", { subagent_type: t2.name }, options.workDir) !== "deny");
|
|
17073
|
-
const
|
|
17224
|
+
const depthLimit = resolveMaxSubagentDepth(settings.raw);
|
|
17225
|
+
const maySpawn = canSpawnSubAgents(depth, options._allowedTools, depthLimit);
|
|
17226
|
+
const agentsCatalogue = maySpawn ? (0, agentTypes_1.summariseAgents)(agentTypes) : "";
|
|
17074
17227
|
const skillsCatalogue = (0, skills_1.summariseSkills)((0, skills_1.loadSkills)(options.workDir));
|
|
17075
17228
|
const planAwareNexrallMd = options.planMode ? planMode_1.PLAN_MODE_INSTRUCTIONS + (options.nexrallMd ? `
|
|
17076
17229
|
|
|
@@ -17220,6 +17373,9 @@ ${options.nexrallMd}` : "") : options.nexrallMd;
|
|
|
17220
17373
|
canWriteSharedMemory: options._allowedTools ? options._allowedTools.has("memory_write") : true,
|
|
17221
17374
|
// no allowlist = main agent = may write
|
|
17222
17375
|
hasOwnAgentStore: !!options._agentMemory,
|
|
17376
|
+
// Withholds the `task` schema and its instructions when this run cannot
|
|
17377
|
+
// delegate — see canSpawnSubAgents.
|
|
17378
|
+
canSpawnSubAgents: maySpawn,
|
|
17223
17379
|
agents: agentsCatalogue || void 0,
|
|
17224
17380
|
skills: skillsCatalogue || void 0,
|
|
17225
17381
|
// Only allow a post-render restart when the caller actually implements the
|
|
@@ -17363,19 +17519,29 @@ ${options.nexrallMd}` : "") : options.nexrallMd;
|
|
|
17363
17519
|
if (!permitted) {
|
|
17364
17520
|
result = { error: deniedReason ?? "Permission denied by user" };
|
|
17365
17521
|
} else if (name === "task") {
|
|
17366
|
-
|
|
17367
|
-
|
|
17368
|
-
|
|
17369
|
-
|
|
17522
|
+
const overBudget = claimSessionSubAgentSlot(options.workDir, options.onNotice ?? options.onText);
|
|
17523
|
+
if (overBudget) {
|
|
17524
|
+
result = { error: overBudget };
|
|
17525
|
+
} else {
|
|
17526
|
+
const childDepth = depth + 1;
|
|
17527
|
+
const { run: limitRun, max: limitMax } = subTaskLimiter(childDepth, options.workDir);
|
|
17528
|
+
const inFlight = _inFlightByDepth.get(childDepth) ?? 0;
|
|
17529
|
+
if (inFlight >= limitMax) {
|
|
17530
|
+
(options.onNotice ?? options.onText)(`\u23F3 Queued: ${limitMax} sub-agent(s) already running at this level, so this one starts when a slot frees up (raise "maxConcurrentSubtasks" in .nexrall/settings.json to widen it).`);
|
|
17370
17531
|
}
|
|
17371
|
-
|
|
17532
|
+
_inFlightByDepth.set(childDepth, inFlight + 1);
|
|
17533
|
+
const started = { value: false };
|
|
17372
17534
|
try {
|
|
17373
|
-
result = await limitRun(() => runSubTask(input, options, agentTypes));
|
|
17535
|
+
result = await limitRun(() => runSubTask(input, options, agentTypes, started));
|
|
17374
17536
|
} finally {
|
|
17375
|
-
|
|
17537
|
+
if (!started.value)
|
|
17538
|
+
refundSessionSubAgentSlot();
|
|
17539
|
+
const n = (_inFlightByDepth.get(childDepth) ?? 1) - 1;
|
|
17540
|
+
if (n > 0)
|
|
17541
|
+
_inFlightByDepth.set(childDepth, n);
|
|
17542
|
+
else
|
|
17543
|
+
_inFlightByDepth.delete(childDepth);
|
|
17376
17544
|
}
|
|
17377
|
-
} else {
|
|
17378
|
-
result = await runSubTask(input, options, agentTypes);
|
|
17379
17545
|
}
|
|
17380
17546
|
} else {
|
|
17381
17547
|
const pre = runToolHooks(hooks.PreToolUse, "PreToolUse", name, input, options.workDir);
|
|
@@ -64351,7 +64517,7 @@ function TrustPrompt({ workDir, signals, onDecide }) {
|
|
|
64351
64517
|
decide(false);
|
|
64352
64518
|
return;
|
|
64353
64519
|
}
|
|
64354
|
-
if (key.return ||
|
|
64520
|
+
if (key.return || /[\r\n]/.test(input)) {
|
|
64355
64521
|
decide(indexRef.current === 0);
|
|
64356
64522
|
}
|
|
64357
64523
|
});
|
|
@@ -64554,7 +64720,7 @@ var InkReadlineAdapter = class extends EventEmitter3 {
|
|
|
64554
64720
|
};
|
|
64555
64721
|
|
|
64556
64722
|
// src/commands/chat.ts
|
|
64557
|
-
var CLI_VERSION = "0.5.
|
|
64723
|
+
var CLI_VERSION = "0.5.60";
|
|
64558
64724
|
var MODEL_LABELS = {
|
|
64559
64725
|
turbo: "Nexrall Turbo",
|
|
64560
64726
|
pro: "Nexrall Pro",
|
|
@@ -65137,6 +65303,9 @@ Set ${TRUST_ENV_VAR}=1 to confirm non-interactively, or run \`nex\` interactivel
|
|
|
65137
65303
|
process.stdout.write("Not trusted \u2014 exiting without loading this folder.\n");
|
|
65138
65304
|
process.exit(0);
|
|
65139
65305
|
}
|
|
65306
|
+
await new Promise((resolve3) => setImmediate(resolve3));
|
|
65307
|
+
if (process.stdin.isTTY)
|
|
65308
|
+
process.stdin.setRawMode(true);
|
|
65140
65309
|
}
|
|
65141
65310
|
const env3 = collectEnv(workDir);
|
|
65142
65311
|
const nexrallMd = readNexrallMd(workDir);
|
|
@@ -65366,6 +65535,7 @@ ${text}` : "");
|
|
|
65366
65535
|
messages = [];
|
|
65367
65536
|
sessionId = crypto.randomBytes(8).toString("hex");
|
|
65368
65537
|
sessionTitle = "";
|
|
65538
|
+
(0, import_code_core4.resetSessionSubAgentBudget)();
|
|
65369
65539
|
console.log(source_default.dim(" Conversation cleared. New session started."));
|
|
65370
65540
|
rl.prompt();
|
|
65371
65541
|
return;
|
|
@@ -66225,7 +66395,7 @@ function pluginSourceRemoveCommand(name, opts) {
|
|
|
66225
66395
|
|
|
66226
66396
|
// src/index.ts
|
|
66227
66397
|
var program2 = new Command();
|
|
66228
|
-
program2.name("nex").description("Nexrall Code \u2014 AI coding assistant (powered by Nexrall)").version("0.5.
|
|
66398
|
+
program2.name("nex").description("Nexrall Code \u2014 AI coding assistant (powered by Nexrall)").version("0.5.60").enablePositionalOptions();
|
|
66229
66399
|
program2.command("auth").description("Login to your Nexrall account").action(authCommand);
|
|
66230
66400
|
program2.command("logout").description("Log out of your Nexrall account").action(logoutCommand);
|
|
66231
66401
|
program2.command("update").description("Update nex to the latest version").option("-c, --check", "Check for updates without installing").option("-y, --yes", "Skip confirmation prompt").action(async (opts) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexrall-code",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.60",
|
|
4
4
|
"description": "Nexrall Code — AI coding assistant for your terminal (headless agent for scripts, CI and automation)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -31,7 +31,15 @@
|
|
|
31
31
|
"engines": {
|
|
32
32
|
"node": ">=18"
|
|
33
33
|
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "node build.js",
|
|
36
|
+
"dev": "tsx src/index.ts",
|
|
37
|
+
"start": "node dist/index.js",
|
|
38
|
+
"test": "tsc --noEmit && tsc --noEmit -p test/tsconfig.json && node --import tsx --test test/*.test.ts test/*.test.mts",
|
|
39
|
+
"release": "node build.js && node scripts/upload-release.cjs"
|
|
40
|
+
},
|
|
34
41
|
"dependencies": {
|
|
42
|
+
"@nexrall/code-core": "workspace:*",
|
|
35
43
|
"chalk": "^5.3.0",
|
|
36
44
|
"commander": "^12.0.0",
|
|
37
45
|
"diff": "^5.2.0",
|
|
@@ -40,8 +48,7 @@
|
|
|
40
48
|
"prompts": "^2.4.2",
|
|
41
49
|
"react": "^19.2.8",
|
|
42
50
|
"readline": "^1.3.0",
|
|
43
|
-
"string-width": "^7.2.0"
|
|
44
|
-
"@nexrall/code-core": "1.4.32"
|
|
51
|
+
"string-width": "^7.2.0"
|
|
45
52
|
},
|
|
46
53
|
"devDependencies": {
|
|
47
54
|
"@aws-sdk/client-s3": "^3.600.0",
|
|
@@ -52,12 +59,5 @@
|
|
|
52
59
|
"esbuild": "^0.20.0",
|
|
53
60
|
"tsx": "^4.7.0",
|
|
54
61
|
"typescript": "^6.0.3"
|
|
55
|
-
},
|
|
56
|
-
"scripts": {
|
|
57
|
-
"build": "node build.js",
|
|
58
|
-
"dev": "tsx src/index.ts",
|
|
59
|
-
"start": "node dist/index.js",
|
|
60
|
-
"test": "tsc --noEmit && tsc --noEmit -p test/tsconfig.json && node --import tsx --test test/*.test.ts test/*.test.mts",
|
|
61
|
-
"release": "node build.js && node scripts/upload-release.cjs"
|
|
62
62
|
}
|
|
63
|
-
}
|
|
63
|
+
}
|