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.
Files changed (2) hide show
  1. package/dist/index.js +403 -10
  2. 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 requestedType = typeof input.subagent_type === "string" ? input.subagent_type : "";
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
- return { output: text || "(sub-task completed with no text output)" };
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 agentTypes = (0, agentTypes_1.loadAgentTypes)(options.workDir);
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 settings = (0, rules_1.loadSettings)(options.workDir);
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: options.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.50";
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.50").enablePositionalOptions();
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.50",
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.25"
44
+ "@nexrall/code-core": "1.4.26"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@aws-sdk/client-s3": "^3.600.0",