nexrall-code 0.5.50 → 0.5.51
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 +403 -10
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -15192,6 +15192,9 @@ var require_rules = __commonJS({
|
|
|
15192
15192
|
case "stock_photo":
|
|
15193
15193
|
vals.push(str(input.path));
|
|
15194
15194
|
break;
|
|
15195
|
+
case "task":
|
|
15196
|
+
vals.push(str(input.subagent_type));
|
|
15197
|
+
break;
|
|
15195
15198
|
default:
|
|
15196
15199
|
pushPath(str(input.path));
|
|
15197
15200
|
break;
|
|
@@ -15232,6 +15235,350 @@ var require_rules = __commonJS({
|
|
|
15232
15235
|
}
|
|
15233
15236
|
});
|
|
15234
15237
|
|
|
15238
|
+
// ../core/dist/agent/planMode.js
|
|
15239
|
+
var require_planMode = __commonJS({
|
|
15240
|
+
"../core/dist/agent/planMode.js"(exports) {
|
|
15241
|
+
"use strict";
|
|
15242
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15243
|
+
exports.PLAN_MODE_INSTRUCTIONS = void 0;
|
|
15244
|
+
exports.isReadOnlyCommand = isReadOnlyCommand;
|
|
15245
|
+
exports.checkPlanMode = checkPlanMode;
|
|
15246
|
+
var READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
15247
|
+
"read_file",
|
|
15248
|
+
"search_files",
|
|
15249
|
+
"glob",
|
|
15250
|
+
"list_directory",
|
|
15251
|
+
"notebook_read",
|
|
15252
|
+
// Planning bookkeeping. todo_write persists only to the session's own todo
|
|
15253
|
+
// list, not the repo, so it stays available — a plan mode that cannot draft
|
|
15254
|
+
// a checklist is missing the point of plan mode.
|
|
15255
|
+
"todo_write",
|
|
15256
|
+
"todo_read",
|
|
15257
|
+
// Reading memory is fine; memory_write is NOT here on purpose. Memory is
|
|
15258
|
+
// durable state that survives the session, so writing it is a real mutation
|
|
15259
|
+
// even though no file in the repo changes.
|
|
15260
|
+
"memory_read",
|
|
15261
|
+
"use_skill",
|
|
15262
|
+
"fetch_url",
|
|
15263
|
+
"web_search",
|
|
15264
|
+
// Delegating research is ALLOWED, and this is safe rather than a hole:
|
|
15265
|
+
// runSubTask passes planMode down, so the sub-agent is under the same lock and
|
|
15266
|
+
// its own write tools are refused by this very function one level deeper.
|
|
15267
|
+
//
|
|
15268
|
+
// Worth allowing rather than blanket-refusing, because plan mode exists to
|
|
15269
|
+
// support deep research and the explorer agent is the cheapest way to do bulk
|
|
15270
|
+
// searching without flooding the main context. Blocking `task` would have made
|
|
15271
|
+
// the mode's headline use case worse, for no security gain.
|
|
15272
|
+
"task",
|
|
15273
|
+
// VS Code language server — all pure queries.
|
|
15274
|
+
"get_symbols",
|
|
15275
|
+
"get_workspace_symbols",
|
|
15276
|
+
"find_references",
|
|
15277
|
+
"go_to_definition",
|
|
15278
|
+
"get_hover",
|
|
15279
|
+
"get_diagnostics",
|
|
15280
|
+
// Reading output from an ALREADY-running background shell. Starting one is
|
|
15281
|
+
// gated with the rest of bash below; draining a buffer is not a new effect.
|
|
15282
|
+
"bash_output"
|
|
15283
|
+
]);
|
|
15284
|
+
var READ_ONLY_BASH = /* @__PURE__ */ new Set([
|
|
15285
|
+
"ls",
|
|
15286
|
+
"cat",
|
|
15287
|
+
"head",
|
|
15288
|
+
"tail",
|
|
15289
|
+
"wc",
|
|
15290
|
+
"file",
|
|
15291
|
+
"stat",
|
|
15292
|
+
"du",
|
|
15293
|
+
"df",
|
|
15294
|
+
"pwd",
|
|
15295
|
+
"which",
|
|
15296
|
+
"type",
|
|
15297
|
+
"echo",
|
|
15298
|
+
"printf",
|
|
15299
|
+
"basename",
|
|
15300
|
+
"dirname",
|
|
15301
|
+
"realpath",
|
|
15302
|
+
"readlink",
|
|
15303
|
+
"grep",
|
|
15304
|
+
"egrep",
|
|
15305
|
+
"fgrep",
|
|
15306
|
+
"rg",
|
|
15307
|
+
"ag",
|
|
15308
|
+
"ack",
|
|
15309
|
+
"find",
|
|
15310
|
+
"fd",
|
|
15311
|
+
"locate",
|
|
15312
|
+
"diff",
|
|
15313
|
+
"comm",
|
|
15314
|
+
"cmp",
|
|
15315
|
+
"sort",
|
|
15316
|
+
"uniq",
|
|
15317
|
+
"cut",
|
|
15318
|
+
"tr",
|
|
15319
|
+
"column",
|
|
15320
|
+
"jq",
|
|
15321
|
+
"yq",
|
|
15322
|
+
"date",
|
|
15323
|
+
"whoami",
|
|
15324
|
+
"hostname",
|
|
15325
|
+
"uname",
|
|
15326
|
+
"env",
|
|
15327
|
+
"printenv",
|
|
15328
|
+
"id",
|
|
15329
|
+
"groups",
|
|
15330
|
+
"ps",
|
|
15331
|
+
"top",
|
|
15332
|
+
"uptime",
|
|
15333
|
+
"free",
|
|
15334
|
+
"node",
|
|
15335
|
+
"python",
|
|
15336
|
+
"python3",
|
|
15337
|
+
"tree",
|
|
15338
|
+
"less",
|
|
15339
|
+
"more",
|
|
15340
|
+
"nl",
|
|
15341
|
+
"tac",
|
|
15342
|
+
"strings",
|
|
15343
|
+
"md5sum",
|
|
15344
|
+
"sha256sum",
|
|
15345
|
+
"true",
|
|
15346
|
+
"false",
|
|
15347
|
+
"test",
|
|
15348
|
+
"sleep",
|
|
15349
|
+
"seq",
|
|
15350
|
+
"expr"
|
|
15351
|
+
]);
|
|
15352
|
+
var READ_ONLY_SUBCOMMANDS = {
|
|
15353
|
+
git: /* @__PURE__ */ new Set([
|
|
15354
|
+
"log",
|
|
15355
|
+
"show",
|
|
15356
|
+
"diff",
|
|
15357
|
+
"status",
|
|
15358
|
+
"blame",
|
|
15359
|
+
"branch",
|
|
15360
|
+
"tag",
|
|
15361
|
+
"remote",
|
|
15362
|
+
"describe",
|
|
15363
|
+
"rev-parse",
|
|
15364
|
+
"rev-list",
|
|
15365
|
+
"ls-files",
|
|
15366
|
+
"ls-tree",
|
|
15367
|
+
"ls-remote",
|
|
15368
|
+
"cat-file",
|
|
15369
|
+
"shortlog",
|
|
15370
|
+
"reflog",
|
|
15371
|
+
"whatchanged",
|
|
15372
|
+
"grep",
|
|
15373
|
+
"config",
|
|
15374
|
+
"check-ignore",
|
|
15375
|
+
"merge-base",
|
|
15376
|
+
"name-rev",
|
|
15377
|
+
"count-objects",
|
|
15378
|
+
"verify-commit"
|
|
15379
|
+
]),
|
|
15380
|
+
// Package managers: only their query verbs.
|
|
15381
|
+
npm: /* @__PURE__ */ new Set(["ls", "list", "view", "info", "outdated", "why", "config", "ping", "search"]),
|
|
15382
|
+
pnpm: /* @__PURE__ */ new Set(["ls", "list", "view", "info", "outdated", "why", "config"]),
|
|
15383
|
+
yarn: /* @__PURE__ */ new Set(["list", "info", "why", "config"]),
|
|
15384
|
+
cargo: /* @__PURE__ */ new Set(["tree", "metadata", "search"]),
|
|
15385
|
+
go: /* @__PURE__ */ new Set(["list", "version", "env", "vet", "doc"]),
|
|
15386
|
+
docker: /* @__PURE__ */ new Set(["ps", "images", "logs", "inspect", "version", "info", "top", "port", "diff", "stats"]),
|
|
15387
|
+
kubectl: /* @__PURE__ */ new Set(["get", "describe", "logs", "explain", "top", "version", "api-resources", "api-versions"]),
|
|
15388
|
+
// gh: read verbs only. `gh run rerun`, `gh pr merge` etc. are excluded, and
|
|
15389
|
+
// the nested-verb check in isReadOnlyCommand handles `gh pr view` vs `gh pr merge`.
|
|
15390
|
+
gh: /* @__PURE__ */ new Set(["browse"])
|
|
15391
|
+
};
|
|
15392
|
+
var READ_ONLY_NESTED = {
|
|
15393
|
+
gh: /* @__PURE__ */ new Set(["view", "list", "status", "diff", "checks"])
|
|
15394
|
+
};
|
|
15395
|
+
var SHELL_CONTROL = /[\n\r;&|`]|\$\(|>>|>|<\(/;
|
|
15396
|
+
function firstWords(command) {
|
|
15397
|
+
return command.trim().split(/\s+/).filter(Boolean);
|
|
15398
|
+
}
|
|
15399
|
+
function isReadOnlyCommand(command) {
|
|
15400
|
+
const cmd = command.trim();
|
|
15401
|
+
if (!cmd)
|
|
15402
|
+
return false;
|
|
15403
|
+
if (SHELL_CONTROL.test(cmd))
|
|
15404
|
+
return false;
|
|
15405
|
+
const words = firstWords(cmd);
|
|
15406
|
+
if (!words.length)
|
|
15407
|
+
return false;
|
|
15408
|
+
let i2 = 0;
|
|
15409
|
+
while (i2 < words.length && /^[A-Za-z_][A-Za-z0-9_]*=/.test(words[i2]))
|
|
15410
|
+
i2++;
|
|
15411
|
+
if (i2 >= words.length)
|
|
15412
|
+
return false;
|
|
15413
|
+
let verb = words[i2];
|
|
15414
|
+
const slash = verb.lastIndexOf("/");
|
|
15415
|
+
if (slash >= 0)
|
|
15416
|
+
verb = verb.slice(slash + 1);
|
|
15417
|
+
if (verb === "sudo" || verb === "doas" || verb === "su")
|
|
15418
|
+
return false;
|
|
15419
|
+
const rest = words.slice(i2 + 1).filter((w) => !w.startsWith("-"));
|
|
15420
|
+
const subs = READ_ONLY_SUBCOMMANDS[verb];
|
|
15421
|
+
if (subs) {
|
|
15422
|
+
const sub = rest[0];
|
|
15423
|
+
if (!sub) {
|
|
15424
|
+
return true;
|
|
15425
|
+
}
|
|
15426
|
+
if (subs.has(sub)) {
|
|
15427
|
+
if (verb === "git" && sub === "config") {
|
|
15428
|
+
const args = words.slice(i2 + 2).filter((w) => !w.startsWith("-"));
|
|
15429
|
+
return args.length <= 1;
|
|
15430
|
+
}
|
|
15431
|
+
return true;
|
|
15432
|
+
}
|
|
15433
|
+
const nested = READ_ONLY_NESTED[verb];
|
|
15434
|
+
if (nested && rest[1] && nested.has(rest[1]))
|
|
15435
|
+
return true;
|
|
15436
|
+
return false;
|
|
15437
|
+
}
|
|
15438
|
+
if (!READ_ONLY_TOOLS.has(verb) && !READ_ONLY_BASH.has(verb))
|
|
15439
|
+
return false;
|
|
15440
|
+
if (verb === "node" || verb === "python" || verb === "python3") {
|
|
15441
|
+
return words.slice(i2 + 1).every((w) => w === "--version" || w === "-V" || w === "-v");
|
|
15442
|
+
}
|
|
15443
|
+
if (verb === "find" && words.some((w) => w === "-exec" || w === "-execdir" || w === "-delete")) {
|
|
15444
|
+
return false;
|
|
15445
|
+
}
|
|
15446
|
+
return true;
|
|
15447
|
+
}
|
|
15448
|
+
function checkPlanMode(tool, input) {
|
|
15449
|
+
if (tool === "bash") {
|
|
15450
|
+
const command = typeof input.command === "string" ? input.command : "";
|
|
15451
|
+
if (input.run_in_background === true) {
|
|
15452
|
+
return {
|
|
15453
|
+
reason: "bash-not-read-only",
|
|
15454
|
+
message: "Plan mode is ON: background processes cannot be started. Finish researching and propose your plan; the user will leave plan mode if they want it carried out."
|
|
15455
|
+
};
|
|
15456
|
+
}
|
|
15457
|
+
if (isReadOnlyCommand(command))
|
|
15458
|
+
return null;
|
|
15459
|
+
return {
|
|
15460
|
+
reason: "bash-not-read-only",
|
|
15461
|
+
message: `Plan mode is ON, so \`bash\` is limited to provably read-only commands and this one was not recognised as such (chained commands, redirection and command substitution are always refused). Do NOT ask the user to approve it and do NOT try a variation to get around this \u2014 it is a session-wide lock, not a per-call prompt. Use read-only inspection instead, and put the command in your plan as a step to run once plan mode is off.`
|
|
15462
|
+
};
|
|
15463
|
+
}
|
|
15464
|
+
if (READ_ONLY_TOOLS.has(tool))
|
|
15465
|
+
return null;
|
|
15466
|
+
return {
|
|
15467
|
+
reason: "mutating-tool",
|
|
15468
|
+
message: `Plan mode is ON, so \`${tool}\` is unavailable \u2014 this session may not modify anything yet. Do NOT ask for approval: no answer the user gives at this prompt can unlock it, because it is a session-wide lock they control directly. Research with read-only tools and finish by proposing a concrete plan (files to change, in order, and how to verify). The user will exit plan mode to let you carry it out.`
|
|
15469
|
+
};
|
|
15470
|
+
}
|
|
15471
|
+
exports.PLAN_MODE_INSTRUCTIONS = [
|
|
15472
|
+
"# PLAN MODE IS ACTIVE",
|
|
15473
|
+
"",
|
|
15474
|
+
"This session is READ-ONLY. You cannot edit files, write files, run mutating commands, or start",
|
|
15475
|
+
"background processes. This is enforced outside your control \u2014 it is not a permission prompt, and",
|
|
15476
|
+
"the user cannot approve an exception from inside this turn.",
|
|
15477
|
+
"",
|
|
15478
|
+
"Therefore:",
|
|
15479
|
+
'- NEVER ask "shall I go ahead and make this change?" \u2014 you cannot, whatever the answer.',
|
|
15480
|
+
'- NEVER attempt a mutating tool "just to see" \u2014 it will be refused and wastes the turn.',
|
|
15481
|
+
"- NEVER try to reach a blocked command another way (a different flag, a script, an interpreter).",
|
|
15482
|
+
"",
|
|
15483
|
+
"Your job is to research thoroughly, then deliver a plan:",
|
|
15484
|
+
"1. What you found \u2014 the specific files, functions and line numbers that matter.",
|
|
15485
|
+
"2. What you propose to change \u2014 file by file, in dependency order.",
|
|
15486
|
+
"3. Risks and unknowns \u2014 what could break, what you could not verify, what you assumed.",
|
|
15487
|
+
"4. How it will be verified \u2014 the exact build/test/lint command that proves it works.",
|
|
15488
|
+
"",
|
|
15489
|
+
'Be concrete. "Update the auth logic" is not a plan; "add a `refreshToken` field to AuthConfig in',
|
|
15490
|
+
'auth/index.ts:42, then thread it through client.ts:118" is. The user will review the plan and',
|
|
15491
|
+
"leave plan mode to have it carried out."
|
|
15492
|
+
].join("\n");
|
|
15493
|
+
}
|
|
15494
|
+
});
|
|
15495
|
+
|
|
15496
|
+
// ../core/dist/agent/agentRegistry.js
|
|
15497
|
+
var require_agentRegistry = __commonJS({
|
|
15498
|
+
"../core/dist/agent/agentRegistry.js"(exports) {
|
|
15499
|
+
"use strict";
|
|
15500
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15501
|
+
exports._limits = void 0;
|
|
15502
|
+
exports.rememberAgent = rememberAgent;
|
|
15503
|
+
exports.updateAgent = updateAgent;
|
|
15504
|
+
exports.getAgent = getAgent;
|
|
15505
|
+
exports.listAgents = listAgents;
|
|
15506
|
+
exports._resetAgentRegistry = _resetAgentRegistry;
|
|
15507
|
+
var MAX_AGENTS = 20;
|
|
15508
|
+
var MAX_TOTAL_BYTES = 8 * 1024 * 1024;
|
|
15509
|
+
var _agents = /* @__PURE__ */ new Map();
|
|
15510
|
+
var _counter = 0;
|
|
15511
|
+
var _seq = 0;
|
|
15512
|
+
function totalBytes() {
|
|
15513
|
+
let n = 0;
|
|
15514
|
+
for (const a of _agents.values())
|
|
15515
|
+
n += a.bytes;
|
|
15516
|
+
return n;
|
|
15517
|
+
}
|
|
15518
|
+
function evictUntilWithinLimits() {
|
|
15519
|
+
while (_agents.size > MAX_AGENTS) {
|
|
15520
|
+
const oldest = _agents.keys().next().value;
|
|
15521
|
+
if (oldest === void 0)
|
|
15522
|
+
break;
|
|
15523
|
+
_agents.delete(oldest);
|
|
15524
|
+
}
|
|
15525
|
+
while (totalBytes() > MAX_TOTAL_BYTES && _agents.size > 1) {
|
|
15526
|
+
const oldest = _agents.keys().next().value;
|
|
15527
|
+
if (oldest === void 0)
|
|
15528
|
+
break;
|
|
15529
|
+
_agents.delete(oldest);
|
|
15530
|
+
}
|
|
15531
|
+
}
|
|
15532
|
+
function sizeOf(messages) {
|
|
15533
|
+
try {
|
|
15534
|
+
return JSON.stringify(messages).length;
|
|
15535
|
+
} catch {
|
|
15536
|
+
return MAX_TOTAL_BYTES;
|
|
15537
|
+
}
|
|
15538
|
+
}
|
|
15539
|
+
function rememberAgent(agentName, description, messages) {
|
|
15540
|
+
const id = `agent_${++_counter}`;
|
|
15541
|
+
const now = Date.now();
|
|
15542
|
+
_agents.set(id, {
|
|
15543
|
+
id,
|
|
15544
|
+
agentName,
|
|
15545
|
+
description,
|
|
15546
|
+
messages,
|
|
15547
|
+
createdAt: now,
|
|
15548
|
+
updatedAt: now,
|
|
15549
|
+
seq: ++_seq,
|
|
15550
|
+
bytes: sizeOf(messages)
|
|
15551
|
+
});
|
|
15552
|
+
evictUntilWithinLimits();
|
|
15553
|
+
return id;
|
|
15554
|
+
}
|
|
15555
|
+
function updateAgent(id, messages) {
|
|
15556
|
+
const existing = _agents.get(id);
|
|
15557
|
+
if (!existing)
|
|
15558
|
+
return;
|
|
15559
|
+
existing.messages = messages;
|
|
15560
|
+
existing.updatedAt = Date.now();
|
|
15561
|
+
existing.seq = ++_seq;
|
|
15562
|
+
existing.bytes = sizeOf(messages);
|
|
15563
|
+
_agents.delete(id);
|
|
15564
|
+
_agents.set(id, existing);
|
|
15565
|
+
evictUntilWithinLimits();
|
|
15566
|
+
}
|
|
15567
|
+
function getAgent(id) {
|
|
15568
|
+
return _agents.get(id);
|
|
15569
|
+
}
|
|
15570
|
+
function listAgents() {
|
|
15571
|
+
return [..._agents.values()].sort((a, b) => b.seq - a.seq);
|
|
15572
|
+
}
|
|
15573
|
+
function _resetAgentRegistry() {
|
|
15574
|
+
_agents.clear();
|
|
15575
|
+
_counter = 0;
|
|
15576
|
+
_seq = 0;
|
|
15577
|
+
}
|
|
15578
|
+
exports._limits = { MAX_AGENTS, MAX_TOTAL_BYTES };
|
|
15579
|
+
}
|
|
15580
|
+
});
|
|
15581
|
+
|
|
15235
15582
|
// ../core/dist/agent/flaky.js
|
|
15236
15583
|
var require_flaky = __commonJS({
|
|
15237
15584
|
"../core/dist/agent/flaky.js"(exports) {
|
|
@@ -15436,6 +15783,8 @@ var require_loop = __commonJS({
|
|
|
15436
15783
|
var agentTypes_1 = require_agentTypes();
|
|
15437
15784
|
var skills_1 = require_skills();
|
|
15438
15785
|
var rules_1 = require_rules();
|
|
15786
|
+
var planMode_1 = require_planMode();
|
|
15787
|
+
var agentRegistry_1 = require_agentRegistry();
|
|
15439
15788
|
var sandbox_1 = require_sandbox();
|
|
15440
15789
|
var index_1 = require_plugins();
|
|
15441
15790
|
var testIntegrity_1 = require_testIntegrity();
|
|
@@ -15756,7 +16105,22 @@ ${tail}`;
|
|
|
15756
16105
|
if (depth >= MAX_TASK_DEPTH) {
|
|
15757
16106
|
return { error: "Sub-agents cannot spawn further sub-agents. Do this work directly, or report back so the main agent can delegate it." };
|
|
15758
16107
|
}
|
|
15759
|
-
const
|
|
16108
|
+
const resumeId = typeof input.resume_agent_id === "string" ? input.resume_agent_id.trim() : "";
|
|
16109
|
+
const resumed = resumeId ? (0, agentRegistry_1.getAgent)(resumeId) : void 0;
|
|
16110
|
+
if (resumeId && !resumed) {
|
|
16111
|
+
return {
|
|
16112
|
+
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.`
|
|
16113
|
+
};
|
|
16114
|
+
}
|
|
16115
|
+
const requestedType = resumed ? resumed.agentName ?? "" : typeof input.subagent_type === "string" ? input.subagent_type : "";
|
|
16116
|
+
if (requestedType) {
|
|
16117
|
+
const decision = (0, rules_1.evaluatePermission)((0, rules_1.loadSettings)(options.workDir).permissions, "task", { subagent_type: requestedType }, options.workDir);
|
|
16118
|
+
if (decision === "deny") {
|
|
16119
|
+
return {
|
|
16120
|
+
error: `The sub-agent "${requestedType}" 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.`
|
|
16121
|
+
};
|
|
16122
|
+
}
|
|
16123
|
+
}
|
|
15760
16124
|
let agent = (0, agentTypes_1.findAgentType)(agentTypes, requestedType);
|
|
15761
16125
|
let knownTypes = agentTypes;
|
|
15762
16126
|
if (requestedType && !agent) {
|
|
@@ -15786,9 +16150,7 @@ ${options.nexrallMd}` : "") : options.nexrallMd;
|
|
|
15786
16150
|
}
|
|
15787
16151
|
return options.requestPermission(req);
|
|
15788
16152
|
};
|
|
15789
|
-
const subMessages = [
|
|
15790
|
-
{ role: "user", content: [{ type: "text", text: prompt2 }] }
|
|
15791
|
-
];
|
|
16153
|
+
const subMessages = resumed ? [...resumed.messages, { role: "user", content: [{ type: "text", text: prompt2 }] }] : [{ role: "user", content: [{ type: "text", text: prompt2 }] }];
|
|
15792
16154
|
const subAbort = { aborted: false };
|
|
15793
16155
|
const timer = setTimeout(() => {
|
|
15794
16156
|
subAbort.aborted = true;
|
|
@@ -15806,6 +16168,9 @@ ${options.nexrallMd}` : "") : options.nexrallMd;
|
|
|
15806
16168
|
editorContext: null,
|
|
15807
16169
|
// fresh isolated context for sub-agent
|
|
15808
16170
|
model: agent?.model ?? options.model,
|
|
16171
|
+
// Plan mode is inherited, never relaxed. If the main agent could spawn a
|
|
16172
|
+
// sub-agent that writes, the lock would be one `task` call from useless.
|
|
16173
|
+
planMode: options.planMode,
|
|
15809
16174
|
nexrallMd: subNexrallMd,
|
|
15810
16175
|
abortSignal: subAbort,
|
|
15811
16176
|
requestPermission: gatedPermission,
|
|
@@ -15854,7 +16219,13 @@ ${partial}` : "",
|
|
|
15854
16219
|
return { error: sections.join("\n\n") };
|
|
15855
16220
|
}
|
|
15856
16221
|
const text = capSubTaskText(extractSubTaskText(result, true));
|
|
15857
|
-
|
|
16222
|
+
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);
|
|
16223
|
+
const body = text || "(sub-task completed with no text output)";
|
|
16224
|
+
return {
|
|
16225
|
+
output: `${body}
|
|
16226
|
+
|
|
16227
|
+
[resumable: this sub-agent is "${agentId}". To ask IT a follow-up \u2014 keeping everything it already read and concluded \u2014 call task again with resume_agent_id="` + agentId + '" instead of writing a new prompt from scratch.]'
|
|
16228
|
+
};
|
|
15858
16229
|
} catch (err) {
|
|
15859
16230
|
const salvaged = (0, types_1.salvageHistory)(err);
|
|
15860
16231
|
if (salvaged) {
|
|
@@ -16236,10 +16607,15 @@ Continue the work from here.` }] });
|
|
|
16236
16607
|
const hooks = loadHooks(options.workDir);
|
|
16237
16608
|
const depth = options._depth ?? 0;
|
|
16238
16609
|
const agentScope = options._agentScope ?? "root";
|
|
16239
|
-
const
|
|
16610
|
+
const settings = (0, rules_1.loadSettings)(options.workDir);
|
|
16611
|
+
const agentTypes = (0, agentTypes_1.loadAgentTypes)(options.workDir).filter((t2) => (0, rules_1.evaluatePermission)(settings.permissions, "task", { subagent_type: t2.name }, options.workDir) !== "deny");
|
|
16240
16612
|
const agentsCatalogue = depth === 0 ? (0, agentTypes_1.summariseAgents)(agentTypes) : "";
|
|
16241
16613
|
const skillsCatalogue = (0, skills_1.summariseSkills)((0, skills_1.loadSkills)(options.workDir));
|
|
16242
|
-
const
|
|
16614
|
+
const planAwareNexrallMd = options.planMode ? planMode_1.PLAN_MODE_INSTRUCTIONS + (options.nexrallMd ? `
|
|
16615
|
+
|
|
16616
|
+
---
|
|
16617
|
+
|
|
16618
|
+
${options.nexrallMd}` : "") : options.nexrallMd;
|
|
16243
16619
|
const sandboxCfg = (0, sandbox_1.parseSandboxConfig)(settings.raw.sandbox) ?? void 0;
|
|
16244
16620
|
const maxIterations = resolveMaxIterations(options.maxIterations, settings.raw);
|
|
16245
16621
|
const autoContinue = resolveAutoContinue(options.autoContinue, settings.raw);
|
|
@@ -16347,7 +16723,7 @@ Continue the work from here.` }] });
|
|
|
16347
16723
|
effort: options.effort,
|
|
16348
16724
|
env: options.env,
|
|
16349
16725
|
editorContext: options.editorContext,
|
|
16350
|
-
nexrallMd:
|
|
16726
|
+
nexrallMd: planAwareNexrallMd,
|
|
16351
16727
|
clientType: options.clientType,
|
|
16352
16728
|
abortSignal: options.abortSignal,
|
|
16353
16729
|
extraTools: options.mcpManager?.getAnthropicTools(),
|
|
@@ -16467,6 +16843,14 @@ Continue the work from here.` }] });
|
|
|
16467
16843
|
options.onToolResult(name, result);
|
|
16468
16844
|
return { block: { ...block, id }, result };
|
|
16469
16845
|
}
|
|
16846
|
+
if (options.planMode) {
|
|
16847
|
+
const refusal = (0, planMode_1.checkPlanMode)(name, input);
|
|
16848
|
+
if (refusal) {
|
|
16849
|
+
result = { error: refusal.message };
|
|
16850
|
+
options.onToolResult(name, result);
|
|
16851
|
+
return { block: { ...block, id }, result };
|
|
16852
|
+
}
|
|
16853
|
+
}
|
|
16470
16854
|
const description = humanDescription(name, input);
|
|
16471
16855
|
let permitted;
|
|
16472
16856
|
let deniedReason = null;
|
|
@@ -18482,6 +18866,8 @@ var require_dist2 = __commonJS({
|
|
|
18482
18866
|
__exportStar(require_manager2(), exports);
|
|
18483
18867
|
__exportStar(require_loader(), exports);
|
|
18484
18868
|
__exportStar(require_agentTypes(), exports);
|
|
18869
|
+
__exportStar(require_planMode(), exports);
|
|
18870
|
+
__exportStar(require_agentRegistry(), exports);
|
|
18485
18871
|
__exportStar(require_rules(), exports);
|
|
18486
18872
|
__exportStar(require_destructive(), exports);
|
|
18487
18873
|
__exportStar(require_plugins(), exports);
|
|
@@ -63558,7 +63944,7 @@ var InkReadlineAdapter = class extends EventEmitter3 {
|
|
|
63558
63944
|
};
|
|
63559
63945
|
|
|
63560
63946
|
// src/commands/chat.ts
|
|
63561
|
-
var CLI_VERSION = "0.5.
|
|
63947
|
+
var CLI_VERSION = "0.5.51";
|
|
63562
63948
|
var MODEL_LABELS = {
|
|
63563
63949
|
turbo: "Nexrall Turbo",
|
|
63564
63950
|
pro: "Nexrall Pro",
|
|
@@ -63829,6 +64215,12 @@ async function runTurn(messages, modelAlias, workDir, abortSignal, env3, nexrall
|
|
|
63829
64215
|
env: env3,
|
|
63830
64216
|
nexrallMd,
|
|
63831
64217
|
mode,
|
|
64218
|
+
// `/mode plan` previously only hinted to the backend — the footer said "plan
|
|
64219
|
+
// mode on" while every write tool stayed live, so the one mode whose entire
|
|
64220
|
+
// promise is "I will not touch anything" was the one not enforced. This
|
|
64221
|
+
// makes it real: the loop refuses mutating tools before the permission
|
|
64222
|
+
// prompt, and sub-agents inherit the lock.
|
|
64223
|
+
planMode: mode === "plan",
|
|
63832
64224
|
effort,
|
|
63833
64225
|
// The backend streams a cumulative output-token count (routes/code.js's
|
|
63834
64226
|
// sendProgress, throttled to ≤5/s) covering thinking, visible text AND
|
|
@@ -63982,6 +64374,7 @@ async function runTurnHeadless(messages, modelAlias, workDir, _abortSignal, env3
|
|
|
63982
64374
|
env: env3,
|
|
63983
64375
|
nexrallMd,
|
|
63984
64376
|
mode,
|
|
64377
|
+
planMode: mode === "plan",
|
|
63985
64378
|
effort,
|
|
63986
64379
|
abortSignal: _abortSignal,
|
|
63987
64380
|
onText: (text) => {
|
|
@@ -65218,7 +65611,7 @@ function pluginSourceRemoveCommand(name, opts) {
|
|
|
65218
65611
|
|
|
65219
65612
|
// src/index.ts
|
|
65220
65613
|
var program2 = new Command();
|
|
65221
|
-
program2.name("nex").description("Nexrall Code \u2014 AI coding assistant (powered by Nexrall)").version("0.5.
|
|
65614
|
+
program2.name("nex").description("Nexrall Code \u2014 AI coding assistant (powered by Nexrall)").version("0.5.51").enablePositionalOptions();
|
|
65222
65615
|
program2.command("auth").description("Login to your Nexrall account").action(authCommand);
|
|
65223
65616
|
program2.command("logout").description("Log out of your Nexrall account").action(logoutCommand);
|
|
65224
65617
|
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.51",
|
|
4
4
|
"description": "Nexrall Code — AI coding assistant for your terminal (headless agent for scripts, CI and automation)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"react": "^19.2.8",
|
|
42
42
|
"readline": "^1.3.0",
|
|
43
43
|
"string-width": "^7.2.0",
|
|
44
|
-
"@nexrall/code-core": "1.4.
|
|
44
|
+
"@nexrall/code-core": "1.4.26"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@aws-sdk/client-s3": "^3.600.0",
|