nexrall-code 0.5.55 → 0.5.57

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 +294 -85
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -15375,6 +15375,63 @@ var require_rules = __commonJS({
15375
15375
  }
15376
15376
  });
15377
15377
 
15378
+ // ../core/dist/permissions/bashClassify.js
15379
+ var require_bashClassify = __commonJS({
15380
+ "../core/dist/permissions/bashClassify.js"(exports) {
15381
+ "use strict";
15382
+ Object.defineProperty(exports, "__esModule", { value: true });
15383
+ exports.bashNeedsRepoLock = bashNeedsRepoLock;
15384
+ var MUTATING_BASH_VERBS = /* @__PURE__ */ new Set([
15385
+ "git",
15386
+ "npm",
15387
+ "pnpm",
15388
+ "yarn",
15389
+ "bun",
15390
+ "cargo",
15391
+ "go",
15392
+ "pip",
15393
+ "pip3",
15394
+ "poetry",
15395
+ "uv",
15396
+ "bundle",
15397
+ "composer",
15398
+ "gradle",
15399
+ "mvn",
15400
+ "make",
15401
+ "terraform",
15402
+ "helm",
15403
+ "docker",
15404
+ "vsce",
15405
+ "tsc",
15406
+ "pytest",
15407
+ "dotnet",
15408
+ "swift",
15409
+ "gem"
15410
+ ]);
15411
+ function bashNeedsRepoLock(command) {
15412
+ if (!command)
15413
+ return false;
15414
+ const segments = command.split(/\|\||&&|[;|&\n()]|\$\(/);
15415
+ for (const seg of segments) {
15416
+ for (const tokenRaw of seg.trim().split(/\s+/)) {
15417
+ const token = tokenRaw.replace(/^["']|["']$/g, "");
15418
+ if (!token)
15419
+ continue;
15420
+ if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(token))
15421
+ continue;
15422
+ if (token === "sudo" || token === "time" || token === "nice" || token === "env")
15423
+ continue;
15424
+ const verb = token.split("/").pop() ?? token;
15425
+ if (MUTATING_BASH_VERBS.has(verb))
15426
+ return true;
15427
+ break;
15428
+ }
15429
+ }
15430
+ return false;
15431
+ }
15432
+ }
15433
+ });
15434
+
15378
15435
  // ../core/dist/agent/planMode.js
15379
15436
  var require_planMode = __commonJS({
15380
15437
  "../core/dist/agent/planMode.js"(exports) {
@@ -15897,12 +15954,15 @@ var require_loop = __commonJS({
15897
15954
  };
15898
15955
  }();
15899
15956
  Object.defineProperty(exports, "__esModule", { value: true });
15900
- exports.VERIFY_CMD_RE = exports.WRITE_TOOL_NAMES = exports.ToolNotAllowedError = exports.AGENT_MEMORY_TOOL_SCHEMA = exports.AGENT_MEMORY_TOOL = exports._stallLimits = void 0;
15957
+ exports.VERIFY_CMD_RE = exports.WRITE_TOOL_NAMES = exports.ToolNotAllowedError = exports.AGENT_MEMORY_TOOL_SCHEMA = exports.AGENT_MEMORY_TOOL = exports._stallLimits = exports.bashNeedsRepoLock = void 0;
15901
15958
  exports.errorRoundSignature = errorRoundSignature;
15902
15959
  exports.executeAgentMemoryWrite = executeAgentMemoryWrite;
15903
15960
  exports.stopReasonNotice = stopReasonNotice;
15904
15961
  exports.resolveMaxIterations = resolveMaxIterations;
15962
+ exports.lockPathsFor = lockPathsFor;
15963
+ exports.resolveMaxConcurrentSubtasks = resolveMaxConcurrentSubtasks;
15905
15964
  exports.createLimiter = createLimiter;
15965
+ exports._resetSubTaskLimiter = _resetSubTaskLimiter;
15906
15966
  exports.resolveSubtaskTimeoutMs = resolveSubtaskTimeoutMs;
15907
15967
  exports.extractSubTaskText = extractSubTaskText;
15908
15968
  exports.capSubTaskText = capSubTaskText;
@@ -15928,6 +15988,10 @@ var require_loop = __commonJS({
15928
15988
  var agentTypes_1 = require_agentTypes();
15929
15989
  var skills_1 = require_skills();
15930
15990
  var rules_1 = require_rules();
15991
+ var bashClassify_1 = require_bashClassify();
15992
+ Object.defineProperty(exports, "bashNeedsRepoLock", { enumerable: true, get: function() {
15993
+ return bashClassify_1.bashNeedsRepoLock;
15994
+ } });
15931
15995
  var planMode_1 = require_planMode();
15932
15996
  var agentRegistry_1 = require_agentRegistry();
15933
15997
  var sandbox_1 = require_sandbox();
@@ -16144,10 +16208,41 @@ ${ctx.repeatError}
16144
16208
  _fileLocks.delete(absPath);
16145
16209
  }
16146
16210
  }
16147
- var MAX_CONCURRENT_SUBTASKS = (() => {
16148
- const raw = Number(process.env.NEXRALL_MAX_CONCURRENT_SUBTASKS);
16149
- return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 4;
16150
- })();
16211
+ async function withFileLocks(absPaths, fn) {
16212
+ const unique = [...new Set(absPaths.filter(Boolean))].sort();
16213
+ if (unique.length === 0)
16214
+ return fn();
16215
+ const [first, ...rest] = unique;
16216
+ return withFileLock(first, () => rest.length ? withFileLocks(rest, fn) : fn());
16217
+ }
16218
+ var WRITE_TOOLS = /* @__PURE__ */ new Set([
16219
+ "write_file",
16220
+ "edit_file",
16221
+ "multi_edit",
16222
+ "delete_file",
16223
+ "move_file",
16224
+ "copy_file",
16225
+ "notebook_edit"
16226
+ ]);
16227
+ var REPO_STATE_LOCK = "\0repo-state";
16228
+ function lockPathsFor(name, input, workDir) {
16229
+ if (!WRITE_TOOLS.has(name))
16230
+ return [];
16231
+ const raw = [input.path, input.source, input.destination, input.dest].filter((p) => typeof p === "string" && p.length > 0);
16232
+ const abs = raw.map((p) => workDir ? path6.resolve(workDir, p) : p);
16233
+ return abs.length ? abs : [name];
16234
+ }
16235
+ var DEFAULT_MAX_CONCURRENT_SUBTASKS = 4;
16236
+ function resolveMaxConcurrentSubtasks(settingsRaw = {}) {
16237
+ const clamp = (n) => Math.min(Math.floor(n), 16);
16238
+ const fromEnv = Number(process.env.NEXRALL_MAX_CONCURRENT_SUBTASKS);
16239
+ if (Number.isFinite(fromEnv) && fromEnv > 0)
16240
+ return clamp(fromEnv);
16241
+ const fromSettings = Number(settingsRaw.maxConcurrentSubtasks);
16242
+ if (Number.isFinite(fromSettings) && fromSettings > 0)
16243
+ return clamp(fromSettings);
16244
+ return DEFAULT_MAX_CONCURRENT_SUBTASKS;
16245
+ }
16151
16246
  function createLimiter(max) {
16152
16247
  let active = 0;
16153
16248
  const queue = [];
@@ -16166,7 +16261,20 @@ ${ctx.repeatError}
16166
16261
  }
16167
16262
  };
16168
16263
  }
16169
- var _subTaskLimit = createLimiter(MAX_CONCURRENT_SUBTASKS);
16264
+ var _subTaskLimitInstance = null;
16265
+ var _subTaskLimitMax = 0;
16266
+ var _inFlightSubTasks = 0;
16267
+ function subTaskLimiter(workDir) {
16268
+ if (!_subTaskLimitInstance) {
16269
+ _subTaskLimitMax = resolveMaxConcurrentSubtasks(workDir ? (0, rules_1.loadSettings)(workDir).raw : {});
16270
+ _subTaskLimitInstance = createLimiter(_subTaskLimitMax);
16271
+ }
16272
+ return { run: _subTaskLimitInstance, max: _subTaskLimitMax };
16273
+ }
16274
+ function _resetSubTaskLimiter() {
16275
+ _subTaskLimitInstance = null;
16276
+ _subTaskLimitMax = 0;
16277
+ }
16170
16278
  function humanDescription(name, input) {
16171
16279
  switch (name) {
16172
16280
  case "read_file":
@@ -17255,7 +17363,20 @@ ${options.nexrallMd}` : "") : options.nexrallMd;
17255
17363
  if (!permitted) {
17256
17364
  result = { error: deniedReason ?? "Permission denied by user" };
17257
17365
  } else if (name === "task") {
17258
- result = depth === 0 ? await _subTaskLimit(() => runSubTask(input, options, agentTypes)) : await runSubTask(input, options, agentTypes);
17366
+ if (depth === 0) {
17367
+ const { run: limitRun, max: limitMax } = subTaskLimiter(options.workDir);
17368
+ if (_inFlightSubTasks >= limitMax) {
17369
+ (options.onNotice ?? options.onText)(`\u23F3 Queued: ${limitMax} sub-agents are already running, so this one starts when a slot frees up (raise "maxConcurrentSubtasks" in .nexrall/settings.json to widen it).`);
17370
+ }
17371
+ _inFlightSubTasks++;
17372
+ try {
17373
+ result = await limitRun(() => runSubTask(input, options, agentTypes));
17374
+ } finally {
17375
+ _inFlightSubTasks--;
17376
+ }
17377
+ } else {
17378
+ result = await runSubTask(input, options, agentTypes);
17379
+ }
17259
17380
  } else {
17260
17381
  const pre = runToolHooks(hooks.PreToolUse, "PreToolUse", name, input, options.workDir);
17261
17382
  if (pre.block) {
@@ -17275,15 +17396,10 @@ ${options.nexrallMd}` : "") : options.nexrallMd;
17275
17396
  result = { output: mcpOutput ?? "" };
17276
17397
  } else {
17277
17398
  options.checkpointManager?.recordBeforeMutation(name, input);
17278
- const WRITE_TOOLS = /* @__PURE__ */ new Set(["write_file", "edit_file", "multi_edit", "delete_file", "move_file", "copy_file", "notebook_edit"]);
17279
17399
  const onStream = options.onToolStreamChunk ? (chunk) => options.onToolStreamChunk(name, chunk) : void 0;
17280
- if (WRITE_TOOLS.has(name)) {
17281
- const targetPath = typeof input.path === "string" ? input.path : typeof input.source === "string" ? input.source : "";
17282
- const absTarget = targetPath && options.workDir ? path6.resolve(options.workDir, targetPath) : targetPath;
17283
- result = await withFileLock(absTarget || name, () => (0, executor_1.executeTool)(name, input, options.abortSignal, sandboxCfg, options.workDir, agentScope, onStream));
17284
- } else {
17285
- result = await (0, executor_1.executeTool)(name, input, options.abortSignal, sandboxCfg, options.workDir, agentScope, onStream);
17286
- }
17400
+ const run = () => (0, executor_1.executeTool)(name, input, options.abortSignal, sandboxCfg, options.workDir, agentScope, onStream);
17401
+ const locks = name === "bash" ? (0, bashClassify_1.bashNeedsRepoLock)(String(input.command ?? "")) ? [REPO_STATE_LOCK] : [] : lockPathsFor(name, input, options.workDir);
17402
+ result = locks.length ? await withFileLocks(locks, run) : await run();
17287
17403
  }
17288
17404
  } catch (err) {
17289
17405
  result = { error: `Tool execution failed: ${err.message}` };
@@ -18512,6 +18628,95 @@ var require_manager2 = __commonJS({
18512
18628
  }
18513
18629
  });
18514
18630
 
18631
+ // ../core/dist/permissions/modePolicy.js
18632
+ var require_modePolicy = __commonJS({
18633
+ "../core/dist/permissions/modePolicy.js"(exports) {
18634
+ "use strict";
18635
+ Object.defineProperty(exports, "__esModule", { value: true });
18636
+ exports.BASH_TOOLS = exports.FILE_MUTATE_TOOLS = exports.FILE_WRITE_TOOLS = exports.READ_ONLY_TOOLS = void 0;
18637
+ exports.isReadOnlyBash = isReadOnlyBash;
18638
+ exports.decide = decide;
18639
+ exports.describeMode = describeMode2;
18640
+ exports.parseMode = parseMode2;
18641
+ var bashClassify_1 = require_bashClassify();
18642
+ exports.READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
18643
+ "read_file",
18644
+ "list_directory",
18645
+ "search_files",
18646
+ "glob",
18647
+ "grep",
18648
+ "fetch_url",
18649
+ "web_search",
18650
+ "bash_output",
18651
+ "kill_shell",
18652
+ "todo_read",
18653
+ "todo_write",
18654
+ "memory_read",
18655
+ "use_skill",
18656
+ "notebook_read",
18657
+ "get_diagnostics",
18658
+ "go_to_definition",
18659
+ "find_references",
18660
+ "get_symbols",
18661
+ "get_workspace_symbols",
18662
+ "get_hover"
18663
+ ]);
18664
+ exports.FILE_WRITE_TOOLS = /* @__PURE__ */ new Set([
18665
+ "write_file",
18666
+ "create_file",
18667
+ "edit_file",
18668
+ "multi_edit",
18669
+ "notebook_edit"
18670
+ ]);
18671
+ exports.FILE_MUTATE_TOOLS = /* @__PURE__ */ new Set([
18672
+ "delete_file",
18673
+ "move_file",
18674
+ "copy_file"
18675
+ ]);
18676
+ exports.BASH_TOOLS = /* @__PURE__ */ new Set(["bash", "run_command", "execute_command"]);
18677
+ function isReadOnlyBash(command) {
18678
+ return !(0, bashClassify_1.bashNeedsRepoLock)(command);
18679
+ }
18680
+ function decide(req) {
18681
+ const { tool, mode } = req;
18682
+ const command = String(req.input.command ?? req.input.cmd ?? "");
18683
+ if (exports.READ_ONLY_TOOLS.has(tool))
18684
+ return "allow";
18685
+ if (exports.BASH_TOOLS.has(tool) && isReadOnlyBash(command) && !req.destructive)
18686
+ return "allow";
18687
+ if (req.destructive)
18688
+ return "confirm";
18689
+ if (mode === "plan")
18690
+ return "deny";
18691
+ if (req.bypass)
18692
+ return "allow";
18693
+ if (exports.FILE_WRITE_TOOLS.has(tool) || exports.FILE_MUTATE_TOOLS.has(tool)) {
18694
+ return mode === "ask" ? "ask" : "allow";
18695
+ }
18696
+ if (exports.BASH_TOOLS.has(tool)) {
18697
+ return mode === "auto" ? "allow" : "ask";
18698
+ }
18699
+ return "ask";
18700
+ }
18701
+ function describeMode2(mode) {
18702
+ switch (mode) {
18703
+ case "plan":
18704
+ return "plan \u2014 read-only, produces a plan for approval";
18705
+ case "ask":
18706
+ return "ask \u2014 approves reads; asks before edits and commands";
18707
+ case "edit":
18708
+ return "edit \u2014 edits files freely; asks before shell commands";
18709
+ case "auto":
18710
+ return "auto \u2014 edits and runs commands; still confirms irreversible actions";
18711
+ }
18712
+ }
18713
+ function parseMode2(raw) {
18714
+ const s2 = String(raw ?? "").trim().toLowerCase();
18715
+ return s2 === "plan" || s2 === "ask" || s2 === "edit" || s2 === "auto" ? s2 : "ask";
18716
+ }
18717
+ }
18718
+ });
18719
+
18515
18720
  // ../core/dist/permissions/destructive.js
18516
18721
  var require_destructive = __commonJS({
18517
18722
  "../core/dist/permissions/destructive.js"(exports) {
@@ -19274,6 +19479,8 @@ var require_dist2 = __commonJS({
19274
19479
  __exportStar(require_planMode(), exports);
19275
19480
  __exportStar(require_agentRegistry(), exports);
19276
19481
  __exportStar(require_rules(), exports);
19482
+ __exportStar(require_modePolicy(), exports);
19483
+ __exportStar(require_bashClassify(), exports);
19277
19484
  __exportStar(require_destructive(), exports);
19278
19485
  __exportStar(require_plugins(), exports);
19279
19486
  __exportStar(require_installer(), exports);
@@ -53599,7 +53806,7 @@ var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
53599
53806
  var source_default = chalk;
53600
53807
 
53601
53808
  // src/index.ts
53602
- var import_code_core5 = __toESM(require_dist2(), 1);
53809
+ var import_code_core6 = __toESM(require_dist2(), 1);
53603
53810
 
53604
53811
  // src/commands/auth.ts
53605
53812
  import * as readline from "readline";
@@ -54686,14 +54893,14 @@ var import_code_core2 = __toESM(require_dist2(), 1);
54686
54893
  var autoApproved = /* @__PURE__ */ new Set();
54687
54894
  var _rules = { allow: [], ask: [], deny: [] };
54688
54895
  var _workDir = process.cwd();
54689
- var _mode = "auto";
54896
+ var _mode = "ask";
54690
54897
  function initPermissions(workDir) {
54691
54898
  _workDir = workDir;
54692
54899
  _rules = (0, import_code_core2.loadSettings)(workDir).permissions;
54693
54900
  return _rules;
54694
54901
  }
54695
54902
  function setMode(mode) {
54696
- _mode = mode || "auto";
54903
+ _mode = (0, import_code_core2.parseMode)(mode);
54697
54904
  }
54698
54905
  function setAutoApprove(category) {
54699
54906
  autoApproved.add(category);
@@ -54708,22 +54915,30 @@ var _replInterface = null;
54708
54915
  function setReadlineInterface(rl) {
54709
54916
  _replInterface = rl;
54710
54917
  }
54918
+ var _promptChain = Promise.resolve();
54919
+ function serialisePrompt(fn) {
54920
+ const next = _promptChain.then(fn, fn);
54921
+ _promptChain = next.catch(() => void 0);
54922
+ return next;
54923
+ }
54711
54924
  function askUser(question) {
54712
- if (_replInterface) {
54713
- const rl = _replInterface;
54925
+ return serialisePrompt(() => {
54926
+ if (_replInterface) {
54927
+ const rl = _replInterface;
54928
+ return new Promise((resolve3) => {
54929
+ rl.question(question, (answer) => resolve3(answer.trim()));
54930
+ });
54931
+ }
54714
54932
  return new Promise((resolve3) => {
54715
- rl.question(question, (answer) => resolve3(answer.trim()));
54716
- });
54717
- }
54718
- return new Promise((resolve3) => {
54719
- const rl = readline2.createInterface({
54720
- input: process.stdin,
54721
- output: process.stderr,
54722
- terminal: true
54723
- });
54724
- rl.question(question, (answer) => {
54725
- rl.close();
54726
- resolve3(answer.trim());
54933
+ const rl = readline2.createInterface({
54934
+ input: process.stdin,
54935
+ output: process.stderr,
54936
+ terminal: true
54937
+ });
54938
+ rl.question(question, (answer) => {
54939
+ rl.close();
54940
+ resolve3(answer.trim());
54941
+ });
54727
54942
  });
54728
54943
  });
54729
54944
  }
@@ -54752,31 +54967,18 @@ async function requestPermission(req) {
54752
54967
  }
54753
54968
  if (decision === "allow")
54754
54969
  return true;
54755
- const readOnlyTools = [
54756
- "read_file",
54757
- "list_directory",
54758
- "search_files",
54759
- "fetch_url",
54760
- "glob",
54761
- "bash_output",
54762
- "kill_shell",
54763
- "todo_read",
54764
- "todo_write",
54765
- "memory_read",
54766
- "memory_write",
54767
- "use_skill",
54768
- "notebook_read",
54769
- "get_diagnostics",
54770
- "go_to_definition",
54771
- "find_references",
54772
- "get_symbols",
54773
- "get_workspace_symbols",
54774
- "get_hover",
54775
- "open_in_browser"
54776
- ];
54777
- if (readOnlyTools.includes(tool))
54970
+ const verdict = (0, import_code_core2.decide)({
54971
+ tool,
54972
+ input,
54973
+ mode: _mode,
54974
+ bypass: isAutoApproved("all"),
54975
+ // The destructive case was already handled above with the strong confirm flow
54976
+ // (type "yes", no "approve all"), so it must not be re-triggered here.
54977
+ destructive: false
54978
+ });
54979
+ if (verdict === "allow")
54778
54980
  return true;
54779
- if (_mode === "plan") {
54981
+ if (verdict === "deny") {
54780
54982
  console.error(source_default.yellow(` \u2298 Plan mode \u2014 refused ${tool} (read-only until you switch mode).`));
54781
54983
  return false;
54782
54984
  }
@@ -54926,6 +55128,9 @@ async function requestPermission(req) {
54926
55128
  return answer === "y" || answer === "yes";
54927
55129
  }
54928
55130
 
55131
+ // src/commands/chat.ts
55132
+ var import_code_core4 = __toESM(require_dist2(), 1);
55133
+
54929
55134
  // src/commands/sessions.ts
54930
55135
  import * as fs3 from "fs";
54931
55136
  import * as path from "path";
@@ -64349,7 +64554,7 @@ var InkReadlineAdapter = class extends EventEmitter3 {
64349
64554
  };
64350
64555
 
64351
64556
  // src/commands/chat.ts
64352
- var CLI_VERSION = "0.5.55";
64557
+ var CLI_VERSION = "0.5.57";
64353
64558
  var MODEL_LABELS = {
64354
64559
  turbo: "Nexrall Turbo",
64355
64560
  pro: "Nexrall Pro",
@@ -65412,11 +65617,15 @@ ${dirList}`;
65412
65617
  case "/mode": {
65413
65618
  const modeArg = arg.toLowerCase();
65414
65619
  if (!modeArg) {
65415
- console.log(source_default.dim(` Current: ${source_default.cyan(agentMode)} Options: ask \xB7 edit \xB7 plan \xB7 auto`));
65620
+ console.log(source_default.dim(` Current: ${source_default.cyan(agentMode)}`));
65621
+ for (const m2 of ["ask", "edit", "auto", "plan"]) {
65622
+ const marker = m2 === agentMode ? source_default.cyan("\u276F") : " ";
65623
+ console.log(` ${marker} ${source_default.bold(m2.padEnd(5))} ${source_default.dim((0, import_code_core4.describeMode)(m2).replace(`${m2} \u2014 `, ""))}`);
65624
+ }
65416
65625
  } else if (["ask", "edit", "plan", "auto"].includes(modeArg)) {
65417
65626
  agentMode = modeArg;
65418
65627
  updateFooter();
65419
- console.log(source_default.green(` Mode \u2192 ${source_default.bold(modeArg)}`));
65628
+ console.log(source_default.green(` Mode \u2192 ${source_default.bold(modeArg)}`) + source_default.dim(` ${(0, import_code_core4.describeMode)(modeArg).replace(`${modeArg} \u2014 `, "")}`));
65420
65629
  } else {
65421
65630
  console.log(source_default.red(` Unknown: ${modeArg}`));
65422
65631
  }
@@ -65706,7 +65915,7 @@ ${caption}` : `[Attached: ${rel}]`;
65706
65915
 
65707
65916
  // src/commands/plugin.ts
65708
65917
  var import_prompts = __toESM(require_prompts3(), 1);
65709
- var import_code_core4 = __toESM(require_dist2(), 1);
65918
+ var import_code_core5 = __toESM(require_dist2(), 1);
65710
65919
  function describeInspection(i2, name, ctx) {
65711
65920
  console.log();
65712
65921
  console.log(source_default.bold(` Plugin: ${name}`) + (i2.meta.version ? source_default.dim(` v${i2.meta.version}`) : ""));
@@ -65782,14 +65991,14 @@ async function pluginInstallCommand(spec, opts) {
65782
65991
  let registryName;
65783
65992
  const isShortName = /^[\w.-]+$/.test(spec.trim()) && !spec.includes("/");
65784
65993
  if (isShortName) {
65785
- const alias = (0, import_code_core4.resolveSourceAlias)(spec.trim(), process.cwd(), { includeProject: true });
65994
+ const alias = (0, import_code_core5.resolveSourceAlias)(spec.trim(), process.cwd(), { includeProject: true });
65786
65995
  if (alias) {
65787
65996
  source2 = alias.spec;
65788
65997
  console.log(source_default.dim(` Source: ${alias.name} (${alias.tier}) \u2190 ${alias.spec}`));
65789
65998
  }
65790
65999
  }
65791
66000
  if (isShortName && source2 === spec) {
65792
- const entry = await (0, import_code_core4.getRegistryPlugin)(spec.trim()).catch(() => null);
66001
+ const entry = await (0, import_code_core5.getRegistryPlugin)(spec.trim()).catch(() => null);
65793
66002
  if (entry) {
65794
66003
  source2 = entry.source;
65795
66004
  registryName = entry.name;
@@ -65804,7 +66013,7 @@ async function pluginInstallCommand(spec, opts) {
65804
66013
  return;
65805
66014
  }
65806
66015
  }
65807
- const res = await (0, import_code_core4.installPlugin)(source2, {
66016
+ const res = await (0, import_code_core5.installPlugin)(source2, {
65808
66017
  scope,
65809
66018
  workDir: process.cwd(),
65810
66019
  name: opts.name ?? registryName,
@@ -65812,7 +66021,7 @@ async function pluginInstallCommand(spec, opts) {
65812
66021
  confirm: (i2, name, ctx) => confirmInstall(i2, name, opts.yes === true, ctx)
65813
66022
  });
65814
66023
  if (registryName)
65815
- (0, import_code_core4.reportInstall)(registryName);
66024
+ (0, import_code_core5.reportInstall)(registryName);
65816
66025
  console.log();
65817
66026
  console.log(source_default.green(` \u2713 Installed "${res.name}" (${res.scope}) \u2192 ${res.dir}`) + (res.sha ? source_default.dim(` @ ${res.sha.slice(0, 7)}`) : ""));
65818
66027
  if (res.inspection.commands.length) {
@@ -65826,7 +66035,7 @@ async function pluginInstallCommand(spec, opts) {
65826
66035
  }
65827
66036
  function pluginRemoveCommand(name, opts) {
65828
66037
  try {
65829
- const dir = (0, import_code_core4.removePlugin)(name, {
66038
+ const dir = (0, import_code_core5.removePlugin)(name, {
65830
66039
  scope: opts.project ? "project" : void 0,
65831
66040
  // no flag → search both scopes
65832
66041
  workDir: process.cwd()
@@ -65839,14 +66048,14 @@ function pluginRemoveCommand(name, opts) {
65839
66048
  }
65840
66049
  async function pluginUpdateCommand(name, opts) {
65841
66050
  const workDir = process.cwd();
65842
- const targets = name ? [name] : (0, import_code_core4.loadPlugins)(workDir).filter((p) => (0, import_code_core4.readReceipt)(p.dir)?.kind === "github").map((p) => p.name);
66051
+ const targets = name ? [name] : (0, import_code_core5.loadPlugins)(workDir).filter((p) => (0, import_code_core5.readReceipt)(p.dir)?.kind === "github").map((p) => p.name);
65843
66052
  if (!targets.length) {
65844
66053
  console.log(source_default.dim(" No updatable plugins (only GitHub-installed plugins with receipts can update)."));
65845
66054
  return;
65846
66055
  }
65847
66056
  for (const t2 of targets) {
65848
66057
  try {
65849
- const res = await (0, import_code_core4.updatePlugin)(t2, {
66058
+ const res = await (0, import_code_core5.updatePlugin)(t2, {
65850
66059
  workDir,
65851
66060
  confirm: (i2, n, ctx) => confirmInstall(i2, n, opts.yes === true, ctx)
65852
66061
  });
@@ -65863,7 +66072,7 @@ function badgeFor(p) {
65863
66072
  }
65864
66073
  async function pluginSearchCommand(query) {
65865
66074
  try {
65866
- const results = await (0, import_code_core4.searchRegistry)(query);
66075
+ const results = await (0, import_code_core5.searchRegistry)(query);
65867
66076
  if (!results.length) {
65868
66077
  console.log(source_default.dim(query ? ` No plugins matching "${query}".` : " Registry is empty."));
65869
66078
  return;
@@ -65886,7 +66095,7 @@ async function pluginSearchCommand(query) {
65886
66095
  }
65887
66096
  async function pluginInfoCommand(name) {
65888
66097
  try {
65889
- const p = await (0, import_code_core4.getRegistryPlugin)(name);
66098
+ const p = await (0, import_code_core5.getRegistryPlugin)(name);
65890
66099
  if (!p) {
65891
66100
  console.error(source_default.red(` \u2717 "${name}" not found in the registry.`));
65892
66101
  process.exitCode = 1;
@@ -65922,7 +66131,7 @@ async function pluginInfoCommand(name) {
65922
66131
  }
65923
66132
  }
65924
66133
  function pluginListCommand() {
65925
- const plugins = (0, import_code_core4.loadPlugins)(process.cwd());
66134
+ const plugins = (0, import_code_core5.loadPlugins)(process.cwd());
65926
66135
  if (!plugins.length) {
65927
66136
  console.log(source_default.dim(" No plugins installed."));
65928
66137
  console.log(source_default.dim(" Install one: nex plugin install owner/repo"));
@@ -65931,10 +66140,10 @@ function pluginListCommand() {
65931
66140
  console.log();
65932
66141
  console.log(source_default.bold(" Installed plugins:"));
65933
66142
  for (const p of plugins) {
65934
- const receipt = (0, import_code_core4.readReceipt)(p.dir);
66143
+ const receipt = (0, import_code_core5.readReceipt)(p.dir);
65935
66144
  const src = receipt ? source_default.dim(` \u2190 ${receipt.source}`) : source_default.dim(" (manual)");
65936
66145
  const at = receipt?.sha ? source_default.dim(` @ ${receipt.sha.slice(0, 7)}`) : "";
65937
- const insp = (0, import_code_core4.inspectPluginDir)(p.dir);
66146
+ const insp = (0, import_code_core5.inspectPluginDir)(p.dir);
65938
66147
  const runs = insp.hasHooks || insp.hasMcp ? source_default.yellow(` \u26A0 ${[insp.hasHooks && "hooks", insp.hasMcp && "mcp"].filter(Boolean).join("+")}`) : "";
65939
66148
  console.log(
65940
66149
  " " + source_default.cyan(p.name.padEnd(24)) + source_default.dim(`${(p.version ?? "").padEnd(10)}${p.scope.padEnd(9)}`) + src + at + runs
@@ -65944,8 +66153,8 @@ function pluginListCommand() {
65944
66153
  }
65945
66154
  function pluginSourceListCommand() {
65946
66155
  const workDir = process.cwd();
65947
- const sources = (0, import_code_core4.loadDeclaredSources)(workDir, { includeProject: true });
65948
- const patterns = (0, import_code_core4.allowedSourcePatterns)();
66156
+ const sources = (0, import_code_core5.loadDeclaredSources)(workDir, { includeProject: true });
66157
+ const patterns = (0, import_code_core5.allowedSourcePatterns)();
65949
66158
  if (patterns) {
65950
66159
  console.log();
65951
66160
  console.log(source_default.bold(" Organisation policy: ") + source_default.dim(`installs restricted to ${patterns.join(", ")}`));
@@ -65960,7 +66169,7 @@ function pluginSourceListCommand() {
65960
66169
  console.log(source_default.bold(" Declared plugin sources:"));
65961
66170
  for (const s2 of sources) {
65962
66171
  const tier = s2.tier === "project" ? source_default.yellow(s2.tier.padEnd(9)) : source_default.dim(s2.tier.padEnd(9));
65963
- const blocked = !(0, import_code_core4.isSourceAllowed)(s2.spec, patterns) ? source_default.red(" \u2717 blocked by policy") : "";
66172
+ const blocked = !(0, import_code_core5.isSourceAllowed)(s2.spec, patterns) ? source_default.red(" \u2717 blocked by policy") : "";
65964
66173
  console.log(" " + source_default.cyan(s2.name.padEnd(20)) + tier + source_default.white(s2.spec) + blocked);
65965
66174
  }
65966
66175
  console.log();
@@ -65970,17 +66179,17 @@ function pluginSourceListCommand() {
65970
66179
  }
65971
66180
  function pluginSourceAddCommand(name, spec, opts) {
65972
66181
  try {
65973
- (0, import_code_core4.parsePluginSource)(spec);
65974
- const patterns = (0, import_code_core4.allowedSourcePatterns)();
65975
- if (patterns && !(0, import_code_core4.isSourceAllowed)(spec, patterns)) {
66182
+ (0, import_code_core5.parsePluginSource)(spec);
66183
+ const patterns = (0, import_code_core5.allowedSourcePatterns)();
66184
+ if (patterns && !(0, import_code_core5.isSourceAllowed)(spec, patterns)) {
65976
66185
  console.error(source_default.red(` \u2717 "${spec}" is not permitted by your organisation's policy.`));
65977
66186
  console.error(source_default.dim(` Allowed: ${patterns.join(", ")}`));
65978
66187
  process.exitCode = 1;
65979
66188
  return;
65980
66189
  }
65981
66190
  const scope = opts.project ? "project" : "user";
65982
- const file = (0, import_code_core4.sourcesFileFor)(scope, process.cwd());
65983
- (0, import_code_core4.writeDeclaredSource)(file, name, spec);
66191
+ const file = (0, import_code_core5.sourcesFileFor)(scope, process.cwd());
66192
+ (0, import_code_core5.writeDeclaredSource)(file, name, spec);
65984
66193
  console.log();
65985
66194
  console.log(source_default.green(` \u2713 Declared "${name}" \u2192 ${spec}`) + source_default.dim(` (${scope})`));
65986
66195
  console.log(source_default.dim(` ${file}`));
@@ -65994,13 +66203,13 @@ function pluginSourceAddCommand(name, spec, opts) {
65994
66203
  function pluginSourceRemoveCommand(name, opts) {
65995
66204
  const workDir = process.cwd();
65996
66205
  const scope = opts.project ? "project" : "user";
65997
- const file = (0, import_code_core4.sourcesFileFor)(scope, workDir);
65998
- if ((0, import_code_core4.removeDeclaredSource)(file, name)) {
66206
+ const file = (0, import_code_core5.sourcesFileFor)(scope, workDir);
66207
+ if ((0, import_code_core5.removeDeclaredSource)(file, name)) {
65999
66208
  console.log(source_default.green(` \u2713 Removed source "${name}" (${scope})`));
66000
66209
  console.log(source_default.dim(" Plugins already installed from it are untouched \u2014 remove them with nex plugin remove <name>"));
66001
66210
  return;
66002
66211
  }
66003
- const found = (0, import_code_core4.resolveSourceAlias)(name, workDir, { includeProject: true });
66212
+ const found = (0, import_code_core5.resolveSourceAlias)(name, workDir, { includeProject: true });
66004
66213
  if (found) {
66005
66214
  console.error(source_default.red(` \u2717 "${name}" is declared in the ${found.tier} tier, not ${scope}.`));
66006
66215
  console.error(source_default.dim(` ${found.file}`));
@@ -66016,7 +66225,7 @@ function pluginSourceRemoveCommand(name, opts) {
66016
66225
 
66017
66226
  // src/index.ts
66018
66227
  var program2 = new Command();
66019
- program2.name("nex").description("Nexrall Code \u2014 AI coding assistant (powered by Nexrall)").version("0.5.55").enablePositionalOptions();
66228
+ program2.name("nex").description("Nexrall Code \u2014 AI coding assistant (powered by Nexrall)").version("0.5.57").enablePositionalOptions();
66020
66229
  program2.command("auth").description("Login to your Nexrall account").action(authCommand);
66021
66230
  program2.command("logout").description("Log out of your Nexrall account").action(logoutCommand);
66022
66231
  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) => {
@@ -66088,7 +66297,7 @@ program2.command("sessions").description("List or delete saved chat sessions").o
66088
66297
  console.log();
66089
66298
  });
66090
66299
  program2.option("-p, --pro", "Use Nexrall Pro (Claude Opus, most capable)").option("-t, --turbo", "Use Nexrall Turbo (Claude Sonnet, fast)").option("-u, --ultra", "Use Ultra (Claude Fable 5, most powerful)").option("-y, --yolo", "Auto-approve all tool calls (no permission prompts)").option("-d, --dir <path>", "Set working directory (default: current directory)").option("-m, --model <name>", "Explicit model: turbo | pro | ultra").option("-r, --resume [id]", "Resume last session, or a specific session id").option("--no-banner", "Skip the ASCII banner (useful in scripts/pipes)").option("--output-format <fmt>", "One-shot output format: text | json | stream-json (implies auto-approve)").argument("[prompt...]", "One-shot prompt \u2014 if omitted, starts interactive mode").action(async (promptParts, options) => {
66091
- if (!(0, import_code_core5.isAuthenticated)()) {
66300
+ if (!(0, import_code_core6.isAuthenticated)()) {
66092
66301
  console.error("Not logged in. Run: nex auth");
66093
66302
  process.exit(1);
66094
66303
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexrall-code",
3
- "version": "0.5.55",
3
+ "version": "0.5.57",
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.30"
44
+ "@nexrall/code-core": "1.4.32"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@aws-sdk/client-s3": "^3.600.0",