nexrall-code 0.5.23 → 0.5.27
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 +390 -31
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -12673,7 +12673,7 @@ Resolve the conflict (remove <<<<<<< / ======= / >>>>>>> markers and keep the in
|
|
|
12673
12673
|
var _bgCounter = 0;
|
|
12674
12674
|
function startBackgroundShell(command, displayCommand, workDir, note) {
|
|
12675
12675
|
const id = `bg_${++_bgCounter}`;
|
|
12676
|
-
const child = (0, child_process_1.spawn)(command, { shell: true, cwd: workDir ?? process.cwd(), env: process.env, detached: true });
|
|
12676
|
+
const child = (0, child_process_1.spawn)(command, { shell: true, cwd: workDir ?? process.cwd(), env: process.env, detached: true, stdio: ["ignore", "pipe", "pipe"] });
|
|
12677
12677
|
const shell = {
|
|
12678
12678
|
id,
|
|
12679
12679
|
command: displayCommand,
|
|
@@ -12800,7 +12800,7 @@ ${fresh || "(no new output)"}${trunc}` };
|
|
|
12800
12800
|
}
|
|
12801
12801
|
return { output: `Background shell ${id} ${shell.status}.` };
|
|
12802
12802
|
}
|
|
12803
|
-
async function bash(input, abortSignal, sandbox, workDir) {
|
|
12803
|
+
async function bash(input, abortSignal, sandbox, workDir, onStream) {
|
|
12804
12804
|
const command = typeof input.command === "string" ? input.command : "";
|
|
12805
12805
|
const _rawDesc = typeof input.description === "string" ? input.description : "";
|
|
12806
12806
|
void _rawDesc.slice(0, 200);
|
|
@@ -12835,7 +12835,8 @@ ${r2.output}`;
|
|
|
12835
12835
|
shell: true,
|
|
12836
12836
|
cwd: workDir ?? process.cwd(),
|
|
12837
12837
|
env: process.env,
|
|
12838
|
-
detached: true
|
|
12838
|
+
detached: true,
|
|
12839
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
12839
12840
|
});
|
|
12840
12841
|
const killTree = (sig) => {
|
|
12841
12842
|
try {
|
|
@@ -12951,8 +12952,22 @@ ${body}` : void 0 }));
|
|
|
12951
12952
|
resolve3(prependNote({ output: body, exitCode: 0 }));
|
|
12952
12953
|
}
|
|
12953
12954
|
};
|
|
12954
|
-
child.stdout?.on("data", (chunk) =>
|
|
12955
|
-
|
|
12955
|
+
child.stdout?.on("data", (chunk) => {
|
|
12956
|
+
const text = chunk.toString("utf-8");
|
|
12957
|
+
appendOutput(text);
|
|
12958
|
+
try {
|
|
12959
|
+
onStream?.(text);
|
|
12960
|
+
} catch {
|
|
12961
|
+
}
|
|
12962
|
+
});
|
|
12963
|
+
child.stderr?.on("data", (chunk) => {
|
|
12964
|
+
const text = chunk.toString("utf-8");
|
|
12965
|
+
appendOutput(text);
|
|
12966
|
+
try {
|
|
12967
|
+
onStream?.(text);
|
|
12968
|
+
} catch {
|
|
12969
|
+
}
|
|
12970
|
+
});
|
|
12956
12971
|
child.on("close", (code, signal) => done(code, signal));
|
|
12957
12972
|
child.on("error", (err) => {
|
|
12958
12973
|
settled = true;
|
|
@@ -14148,12 +14163,12 @@ ${expanded}` };
|
|
|
14148
14163
|
"memory_read",
|
|
14149
14164
|
"use_skill"
|
|
14150
14165
|
]);
|
|
14151
|
-
async function executeTool(name, input, abortSignal, sandbox, workDir, agentScope) {
|
|
14166
|
+
async function executeTool(name, input, abortSignal, sandbox, workDir, agentScope, onStream) {
|
|
14152
14167
|
if (!TOOL_MAP[name])
|
|
14153
14168
|
return { error: `Unknown tool: ${name}` };
|
|
14154
14169
|
try {
|
|
14155
14170
|
if (name === "bash")
|
|
14156
|
-
return await bash(input, abortSignal, sandbox, workDir);
|
|
14171
|
+
return await bash(input, abortSignal, sandbox, workDir, input.run_in_background === true ? void 0 : onStream);
|
|
14157
14172
|
if (name === "todo_write")
|
|
14158
14173
|
return await todoWrite(input, agentScope);
|
|
14159
14174
|
if (name === "todo_read")
|
|
@@ -14218,7 +14233,7 @@ var require_agentTypes = __commonJS({
|
|
|
14218
14233
|
};
|
|
14219
14234
|
}();
|
|
14220
14235
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
14221
|
-
exports2.loadAgentTypes =
|
|
14236
|
+
exports2.loadAgentTypes = loadAgentTypes2;
|
|
14222
14237
|
exports2.summariseAgents = summariseAgents;
|
|
14223
14238
|
exports2.findAgentType = findAgentType;
|
|
14224
14239
|
var fs6 = __importStar(require("fs"));
|
|
@@ -14297,7 +14312,7 @@ var require_agentTypes = __commonJS({
|
|
|
14297
14312
|
}
|
|
14298
14313
|
}
|
|
14299
14314
|
}
|
|
14300
|
-
function
|
|
14315
|
+
function loadAgentTypes2(workDir) {
|
|
14301
14316
|
const out = /* @__PURE__ */ new Map();
|
|
14302
14317
|
loadDir(path5.join(workDir, ".nexrall", "agents"), "project", out);
|
|
14303
14318
|
loadDir(path5.join(os5.homedir(), ".nexrall", "agents"), "global", out);
|
|
@@ -14718,14 +14733,16 @@ var require_loop = __commonJS({
|
|
|
14718
14733
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
14719
14734
|
exports2.VERIFY_CMD_RE = exports2.WRITE_TOOL_NAMES = void 0;
|
|
14720
14735
|
exports2.resolveMaxIterations = resolveMaxIterations;
|
|
14721
|
-
exports2.
|
|
14736
|
+
exports2.contextWindowFor = contextWindowFor2;
|
|
14737
|
+
exports2.compactionThresholds = compactionThresholds2;
|
|
14738
|
+
exports2.estimateBodyBytes = estimateBodyBytes2;
|
|
14722
14739
|
exports2.findSafeCutIndex = findSafeCutIndex;
|
|
14723
14740
|
exports2.transcriptOf = transcriptOf;
|
|
14724
14741
|
exports2.createLedger = createLedger;
|
|
14725
14742
|
exports2.ledgerRecord = ledgerRecord;
|
|
14726
14743
|
exports2.ledgerSummary = ledgerSummary;
|
|
14727
14744
|
exports2.pruneOldToolResults = pruneOldToolResults;
|
|
14728
|
-
exports2.estimateTokensRough =
|
|
14745
|
+
exports2.estimateTokensRough = estimateTokensRough2;
|
|
14729
14746
|
exports2.compactMessagesForResume = compactMessagesForResume2;
|
|
14730
14747
|
exports2.runAgentLoop = runAgentLoop2;
|
|
14731
14748
|
exports2.trimToResumableBoundary = trimToResumableBoundary;
|
|
@@ -14961,6 +14978,7 @@ var require_loop = __commonJS({
|
|
|
14961
14978
|
}
|
|
14962
14979
|
var MAX_TASK_DEPTH = 2;
|
|
14963
14980
|
var _subTaskCounter = 0;
|
|
14981
|
+
var SUBTASK_TIMEOUT_MS = Number(process.env.NEXRALL_SUBTASK_TIMEOUT_MS) > 0 ? Number(process.env.NEXRALL_SUBTASK_TIMEOUT_MS) : 10 * 60 * 1e3;
|
|
14964
14982
|
async function runSubTask(input, options, agentTypes) {
|
|
14965
14983
|
const prompt2 = typeof input.prompt === "string" ? input.prompt.trim() : "";
|
|
14966
14984
|
if (!prompt2)
|
|
@@ -14990,6 +15008,14 @@ ${options.nexrallMd}` : "") : options.nexrallMd;
|
|
|
14990
15008
|
const subMessages = [
|
|
14991
15009
|
{ role: "user", content: [{ type: "text", text: prompt2 }] }
|
|
14992
15010
|
];
|
|
15011
|
+
const subAbort = { aborted: false };
|
|
15012
|
+
const timer = setTimeout(() => {
|
|
15013
|
+
subAbort.aborted = true;
|
|
15014
|
+
}, SUBTASK_TIMEOUT_MS);
|
|
15015
|
+
const parentAbortPoll = setInterval(() => {
|
|
15016
|
+
if (options.abortSignal?.aborted)
|
|
15017
|
+
subAbort.aborted = true;
|
|
15018
|
+
}, 250);
|
|
14993
15019
|
try {
|
|
14994
15020
|
const result = await runAgentLoop2(subMessages, {
|
|
14995
15021
|
...options,
|
|
@@ -15000,6 +15026,7 @@ ${options.nexrallMd}` : "") : options.nexrallMd;
|
|
|
15000
15026
|
// fresh isolated context for sub-agent
|
|
15001
15027
|
model: agent?.model ?? options.model,
|
|
15002
15028
|
nexrallMd: subNexrallMd,
|
|
15029
|
+
abortSignal: subAbort,
|
|
15003
15030
|
requestPermission: gatedPermission,
|
|
15004
15031
|
onText: () => {
|
|
15005
15032
|
},
|
|
@@ -15025,11 +15052,15 @@ ${options.nexrallMd}` : "") : options.nexrallMd;
|
|
|
15025
15052
|
// when the name was already labelled, and mixed display concerns into the data layer).
|
|
15026
15053
|
onToolUse: (n, i2) => options.onToolUse(n, i2, true),
|
|
15027
15054
|
onToolResult: (n, r2) => options.onToolResult(n, r2, true),
|
|
15055
|
+
onToolStreamChunk: (n, c) => options.onToolStreamChunk?.(n, c, true),
|
|
15028
15056
|
// Forward thinking so the UI shows the indicator while sub-agent reasons
|
|
15029
15057
|
onThinking: (text2) => options.onThinking?.(text2),
|
|
15030
15058
|
onThinkingDelta: (text2) => options.onThinkingDelta?.(text2),
|
|
15031
15059
|
onThinkingProgress: (tok) => options.onThinkingProgress?.(tok)
|
|
15032
15060
|
});
|
|
15061
|
+
if (subAbort.aborted && !options.abortSignal?.aborted) {
|
|
15062
|
+
return { error: `Sub-task stalled and was stopped after ${Math.round(SUBTASK_TIMEOUT_MS / 6e4)} minutes with no completion. Consider breaking it into smaller sub-tasks or investigating what it may have been stuck on (a hung command, an unresponsive MCP/tool call, or a very large scope).` };
|
|
15063
|
+
}
|
|
15033
15064
|
const lastAssistant = [...result].reverse().find((m2) => m2.role === "assistant");
|
|
15034
15065
|
let text = (lastAssistant?.content ?? []).filter((b) => b.type === "text").map((b) => b.text).join("").trim();
|
|
15035
15066
|
const SUBTASK_MAX = 48e3;
|
|
@@ -15045,6 +15076,9 @@ ${tail}`;
|
|
|
15045
15076
|
return { output: text || "(sub-task completed with no text output)" };
|
|
15046
15077
|
} catch (err) {
|
|
15047
15078
|
return { error: `Sub-task failed: ${err.message}` };
|
|
15079
|
+
} finally {
|
|
15080
|
+
clearTimeout(timer);
|
|
15081
|
+
clearInterval(parentAbortPoll);
|
|
15048
15082
|
}
|
|
15049
15083
|
}
|
|
15050
15084
|
var MODEL_CONTEXT_TOKENS = {
|
|
@@ -15052,16 +15086,22 @@ ${tail}`;
|
|
|
15052
15086
|
pro: 1e6,
|
|
15053
15087
|
ultra: 1e6
|
|
15054
15088
|
};
|
|
15089
|
+
function contextWindowFor2(model) {
|
|
15090
|
+
return MODEL_CONTEXT_TOKENS[model ?? "turbo"] ?? 1e6;
|
|
15091
|
+
}
|
|
15055
15092
|
function envFraction(name, fallback) {
|
|
15056
15093
|
const v = Number(process.env[name]);
|
|
15057
15094
|
return Number.isFinite(v) && v > 0 && v < 1 ? v : fallback;
|
|
15058
15095
|
}
|
|
15059
15096
|
var AUTO_PRUNE_THRESHOLD = envFraction("NEXRALL_PRUNE_THRESHOLD", 0.35);
|
|
15060
15097
|
var AUTO_COMPACT_THRESHOLD = envFraction("NEXRALL_COMPACT_THRESHOLD", 0.8);
|
|
15098
|
+
function compactionThresholds2() {
|
|
15099
|
+
return { prune: AUTO_PRUNE_THRESHOLD, compact: AUTO_COMPACT_THRESHOLD };
|
|
15100
|
+
}
|
|
15061
15101
|
var PRUNE_MIN_RECLAIM_BYTES = 256 * 1024;
|
|
15062
15102
|
var COMPACT_KEEP_MIN = 6;
|
|
15063
15103
|
var MAX_BODY_BYTES = 8 * 1024 * 1024;
|
|
15064
|
-
function
|
|
15104
|
+
function estimateBodyBytes2(messages) {
|
|
15065
15105
|
try {
|
|
15066
15106
|
return Buffer.byteLength(JSON.stringify(messages), "utf-8");
|
|
15067
15107
|
} catch {
|
|
@@ -15327,8 +15367,8 @@ Continue the work from here.` }] });
|
|
|
15327
15367
|
}
|
|
15328
15368
|
}
|
|
15329
15369
|
var RESUME_CHARS_PER_TOKEN = 4;
|
|
15330
|
-
function
|
|
15331
|
-
return Math.ceil(
|
|
15370
|
+
function estimateTokensRough2(messages) {
|
|
15371
|
+
return Math.ceil(estimateBodyBytes2(messages) / RESUME_CHARS_PER_TOKEN);
|
|
15332
15372
|
}
|
|
15333
15373
|
async function compactMessagesForResume2(messages, opts) {
|
|
15334
15374
|
if (messages.length <= COMPACT_KEEP_MIN + 2)
|
|
@@ -15337,8 +15377,8 @@ Continue the work from here.` }] });
|
|
|
15337
15377
|
if (!resolveAutoCompact(void 0, settings.raw))
|
|
15338
15378
|
return false;
|
|
15339
15379
|
const contextWindow = MODEL_CONTEXT_TOKENS[opts.model ?? "turbo"] ?? 1e6;
|
|
15340
|
-
let bodyBytes =
|
|
15341
|
-
let tokenGuess =
|
|
15380
|
+
let bodyBytes = estimateBodyBytes2(messages);
|
|
15381
|
+
let tokenGuess = estimateTokensRough2(messages);
|
|
15342
15382
|
const overPruneThreshold = () => tokenGuess > contextWindow * AUTO_PRUNE_THRESHOLD || bodyBytes > MAX_BODY_BYTES;
|
|
15343
15383
|
const overCompactThreshold = () => tokenGuess > contextWindow * AUTO_COMPACT_THRESHOLD || bodyBytes > MAX_BODY_BYTES;
|
|
15344
15384
|
if (!overPruneThreshold())
|
|
@@ -15347,8 +15387,8 @@ Continue the work from here.` }] });
|
|
|
15347
15387
|
if (messages.length > PRUNE_KEEP_RECENT + 2) {
|
|
15348
15388
|
const reclaimed = pruneOldToolResults(messages, PRUNE_MIN_RECLAIM_BYTES);
|
|
15349
15389
|
if (reclaimed > 0) {
|
|
15350
|
-
bodyBytes =
|
|
15351
|
-
tokenGuess =
|
|
15390
|
+
bodyBytes = estimateBodyBytes2(messages);
|
|
15391
|
+
tokenGuess = estimateTokensRough2(messages);
|
|
15352
15392
|
compacted = true;
|
|
15353
15393
|
opts.onNotice?.(`
|
|
15354
15394
|
\u267B\uFE0F Trimmed ~${(reclaimed / (1024 * 1024)).toFixed(1)}MB of older tool output before resuming this chat.
|
|
@@ -15376,8 +15416,8 @@ Continue the work from here.` }] });
|
|
|
15376
15416
|
if (!did)
|
|
15377
15417
|
break;
|
|
15378
15418
|
compacted = true;
|
|
15379
|
-
bodyBytes =
|
|
15380
|
-
tokenGuess =
|
|
15419
|
+
bodyBytes = estimateBodyBytes2(messages);
|
|
15420
|
+
tokenGuess = estimateTokensRough2(messages);
|
|
15381
15421
|
}
|
|
15382
15422
|
if (compacted) {
|
|
15383
15423
|
opts.onNotice?.(`
|
|
@@ -15422,14 +15462,14 @@ Continue the work from here.` }] });
|
|
|
15422
15462
|
for (; iteration < budget; iteration++) {
|
|
15423
15463
|
if (options.abortSignal?.aborted)
|
|
15424
15464
|
break;
|
|
15425
|
-
let bodyBytes =
|
|
15465
|
+
let bodyBytes = estimateBodyBytes2(messages);
|
|
15426
15466
|
const prunePressure = lastPromptTokens > contextWindow * AUTO_PRUNE_THRESHOLD;
|
|
15427
15467
|
const tokenPressure = lastPromptTokens > contextWindow * AUTO_COMPACT_THRESHOLD;
|
|
15428
15468
|
let bytePressure = bodyBytes > MAX_BODY_BYTES;
|
|
15429
15469
|
if (autoCompact && !compacting && (prunePressure || bytePressure) && messages.length > PRUNE_KEEP_RECENT + 2) {
|
|
15430
15470
|
const reclaimed = pruneOldToolResults(messages, PRUNE_MIN_RECLAIM_BYTES);
|
|
15431
15471
|
if (reclaimed > 0) {
|
|
15432
|
-
bodyBytes =
|
|
15472
|
+
bodyBytes = estimateBodyBytes2(messages);
|
|
15433
15473
|
bytePressure = bodyBytes > MAX_BODY_BYTES;
|
|
15434
15474
|
(options.onNotice ?? options.onText)(`\u267B\uFE0F Trimmed ~${(reclaimed / (1024 * 1024)).toFixed(1)}MB of already-processed tool output to keep this chat cheap to continue.`);
|
|
15435
15475
|
}
|
|
@@ -15649,12 +15689,13 @@ Continue the work from here.` }] });
|
|
|
15649
15689
|
} else {
|
|
15650
15690
|
options.checkpointManager?.recordBeforeMutation(name, input);
|
|
15651
15691
|
const WRITE_TOOLS = /* @__PURE__ */ new Set(["write_file", "edit_file", "multi_edit", "delete_file", "move_file", "copy_file", "notebook_edit"]);
|
|
15692
|
+
const onStream = options.onToolStreamChunk ? (chunk) => options.onToolStreamChunk(name, chunk) : void 0;
|
|
15652
15693
|
if (WRITE_TOOLS.has(name)) {
|
|
15653
15694
|
const targetPath = typeof input.path === "string" ? input.path : typeof input.source === "string" ? input.source : "";
|
|
15654
15695
|
const absTarget = targetPath && options.workDir ? path5.resolve(options.workDir, targetPath) : targetPath;
|
|
15655
|
-
result = await withFileLock(absTarget || name, () => (0, executor_1.executeTool)(name, input, options.abortSignal, sandboxCfg, options.workDir, agentScope));
|
|
15696
|
+
result = await withFileLock(absTarget || name, () => (0, executor_1.executeTool)(name, input, options.abortSignal, sandboxCfg, options.workDir, agentScope, onStream));
|
|
15656
15697
|
} else {
|
|
15657
|
-
result = await (0, executor_1.executeTool)(name, input, options.abortSignal, sandboxCfg, options.workDir, agentScope);
|
|
15698
|
+
result = await (0, executor_1.executeTool)(name, input, options.abortSignal, sandboxCfg, options.workDir, agentScope, onStream);
|
|
15658
15699
|
}
|
|
15659
15700
|
}
|
|
15660
15701
|
} catch (err) {
|
|
@@ -16323,7 +16364,7 @@ var require_manager = __commonJS({
|
|
|
16323
16364
|
var httpClient_1 = require_httpClient();
|
|
16324
16365
|
var sseClient_1 = require_sseClient();
|
|
16325
16366
|
var index_1 = require_plugins();
|
|
16326
|
-
var
|
|
16367
|
+
var McpManager2 = class _McpManager {
|
|
16327
16368
|
constructor() {
|
|
16328
16369
|
this._clients = /* @__PURE__ */ new Map();
|
|
16329
16370
|
this._toolMap = /* @__PURE__ */ new Map();
|
|
@@ -16496,7 +16537,7 @@ var require_manager = __commonJS({
|
|
|
16496
16537
|
this._needsAuth.clear();
|
|
16497
16538
|
}
|
|
16498
16539
|
};
|
|
16499
|
-
exports2.McpManager =
|
|
16540
|
+
exports2.McpManager = McpManager2;
|
|
16500
16541
|
}
|
|
16501
16542
|
});
|
|
16502
16543
|
|
|
@@ -23365,6 +23406,49 @@ function formatToolUse(name, input) {
|
|
|
23365
23406
|
const argDisplay = primaryArg ? source_default.dim(" ") + source_default.white(String(primaryArg).replace(/\n/g, "\u21B5").slice(0, 80)) : "";
|
|
23366
23407
|
return source_default.yellow(icons.tool) + " " + source_default.bold(name) + argDisplay;
|
|
23367
23408
|
}
|
|
23409
|
+
var ToolStreamPrinter = class _ToolStreamPrinter {
|
|
23410
|
+
carry = "";
|
|
23411
|
+
linesShown = 0;
|
|
23412
|
+
// Cap visible lines per command so a runaway/very chatty process (e.g. a
|
|
23413
|
+
// build tool re-printing a progress bar thousands of times) doesn't flood
|
|
23414
|
+
// the terminal — the full output is still available afterward via
|
|
23415
|
+
// formatToolResult's summary and, for large output, the spill file.
|
|
23416
|
+
static MAX_LINES = 200;
|
|
23417
|
+
capped = false;
|
|
23418
|
+
feed(chunk) {
|
|
23419
|
+
if (this.capped)
|
|
23420
|
+
return;
|
|
23421
|
+
this.carry += chunk;
|
|
23422
|
+
const lines = this.carry.split("\n");
|
|
23423
|
+
this.carry = lines.pop() ?? "";
|
|
23424
|
+
for (const line of lines) {
|
|
23425
|
+
if (!this.printLine(line))
|
|
23426
|
+
return;
|
|
23427
|
+
}
|
|
23428
|
+
}
|
|
23429
|
+
printLine(line) {
|
|
23430
|
+
if (this.linesShown >= _ToolStreamPrinter.MAX_LINES) {
|
|
23431
|
+
if (!this.capped) {
|
|
23432
|
+
this.capped = true;
|
|
23433
|
+
process.stdout.write(source_default.dim(" \u2502 \u2026 output continues (full log in the result above once finished)\n"));
|
|
23434
|
+
}
|
|
23435
|
+
return false;
|
|
23436
|
+
}
|
|
23437
|
+
this.linesShown++;
|
|
23438
|
+
process.stdout.write(source_default.dim(" \u2502 ") + source_default.gray(line.slice(0, 300)) + "\n");
|
|
23439
|
+
return true;
|
|
23440
|
+
}
|
|
23441
|
+
flush() {
|
|
23442
|
+
if (!this.capped && this.carry)
|
|
23443
|
+
this.printLine(this.carry);
|
|
23444
|
+
this.carry = "";
|
|
23445
|
+
}
|
|
23446
|
+
reset() {
|
|
23447
|
+
this.carry = "";
|
|
23448
|
+
this.linesShown = 0;
|
|
23449
|
+
this.capped = false;
|
|
23450
|
+
}
|
|
23451
|
+
};
|
|
23368
23452
|
function formatToolResult(name, result, durationMs) {
|
|
23369
23453
|
if (result.error) {
|
|
23370
23454
|
return source_default.red(icons.cross) + " " + source_default.dim(name) + source_default.dim(" \xB7 ") + source_default.red("error") + source_default.dim(` \xB7 ${durationMs}ms`);
|
|
@@ -23385,6 +23469,77 @@ function formatUsage(outputTokens) {
|
|
|
23385
23469
|
return source_default.dim(`\u2193 ${tok} tokens`);
|
|
23386
23470
|
}
|
|
23387
23471
|
|
|
23472
|
+
// src/ui/paste.ts
|
|
23473
|
+
var PASTE_START = "\x1B[200~";
|
|
23474
|
+
var PASTE_END = "\x1B[201~";
|
|
23475
|
+
function enableBracketedPaste() {
|
|
23476
|
+
if (process.stdout.isTTY)
|
|
23477
|
+
process.stdout.write("\x1B[?2004h");
|
|
23478
|
+
}
|
|
23479
|
+
function disableBracketedPaste() {
|
|
23480
|
+
if (process.stdout.isTTY)
|
|
23481
|
+
process.stdout.write("\x1B[?2004l");
|
|
23482
|
+
}
|
|
23483
|
+
function installPasteHandling(rl, stdin) {
|
|
23484
|
+
const originalListeners = stdin.listeners("data");
|
|
23485
|
+
for (const l of originalListeners)
|
|
23486
|
+
stdin.removeListener("data", l);
|
|
23487
|
+
const forward = (buf) => {
|
|
23488
|
+
if (!buf.length)
|
|
23489
|
+
return;
|
|
23490
|
+
for (const l of originalListeners)
|
|
23491
|
+
l.call(stdin, buf);
|
|
23492
|
+
};
|
|
23493
|
+
let buffering = false;
|
|
23494
|
+
let buffer = "";
|
|
23495
|
+
const insertPastedText = (text) => {
|
|
23496
|
+
if (!text)
|
|
23497
|
+
return;
|
|
23498
|
+
const flattened = text.replace(/\r\n|\r|\n/g, " ");
|
|
23499
|
+
const anyRl = rl;
|
|
23500
|
+
if (typeof anyRl._insertString === "function") {
|
|
23501
|
+
anyRl._insertString(flattened);
|
|
23502
|
+
} else {
|
|
23503
|
+
rl.write(flattened);
|
|
23504
|
+
}
|
|
23505
|
+
};
|
|
23506
|
+
const onData = (chunk) => {
|
|
23507
|
+
let text = chunk.toString("utf-8");
|
|
23508
|
+
for (; ; ) {
|
|
23509
|
+
if (!buffering) {
|
|
23510
|
+
const startIdx = text.indexOf(PASTE_START);
|
|
23511
|
+
if (startIdx === -1) {
|
|
23512
|
+
forward(Buffer.from(text, "utf-8"));
|
|
23513
|
+
return;
|
|
23514
|
+
}
|
|
23515
|
+
const before = text.slice(0, startIdx);
|
|
23516
|
+
forward(Buffer.from(before, "utf-8"));
|
|
23517
|
+
text = text.slice(startIdx + PASTE_START.length);
|
|
23518
|
+
buffering = true;
|
|
23519
|
+
buffer = "";
|
|
23520
|
+
}
|
|
23521
|
+
const endIdx = text.indexOf(PASTE_END);
|
|
23522
|
+
if (endIdx === -1) {
|
|
23523
|
+
buffer += text;
|
|
23524
|
+
return;
|
|
23525
|
+
}
|
|
23526
|
+
buffer += text.slice(0, endIdx);
|
|
23527
|
+
insertPastedText(buffer);
|
|
23528
|
+
buffer = "";
|
|
23529
|
+
buffering = false;
|
|
23530
|
+
text = text.slice(endIdx + PASTE_END.length);
|
|
23531
|
+
if (!text)
|
|
23532
|
+
return;
|
|
23533
|
+
}
|
|
23534
|
+
};
|
|
23535
|
+
stdin.on("data", onData);
|
|
23536
|
+
return () => {
|
|
23537
|
+
stdin.removeListener("data", onData);
|
|
23538
|
+
for (const l of originalListeners)
|
|
23539
|
+
stdin.on("data", l);
|
|
23540
|
+
};
|
|
23541
|
+
}
|
|
23542
|
+
|
|
23388
23543
|
// src/permissions/handler.ts
|
|
23389
23544
|
var readline2 = __toESM(require("readline"));
|
|
23390
23545
|
var fs2 = __toESM(require("fs"));
|
|
@@ -24166,7 +24321,7 @@ async function requestPermission(req) {
|
|
|
24166
24321
|
var fs3 = __toESM(require("fs"));
|
|
24167
24322
|
var path = __toESM(require("path"));
|
|
24168
24323
|
var os2 = __toESM(require("os"));
|
|
24169
|
-
var SESSIONS_DIR = path.join(os2.homedir(), ".nexrall", "cli-sessions");
|
|
24324
|
+
var SESSIONS_DIR = process.env.NEXRALL_CLI_SESSIONS_DIR || path.join(os2.homedir(), ".nexrall", "cli-sessions");
|
|
24170
24325
|
function ensureDir() {
|
|
24171
24326
|
fs3.mkdirSync(SESSIONS_DIR, { recursive: true });
|
|
24172
24327
|
}
|
|
@@ -24482,10 +24637,17 @@ var Spinner = class {
|
|
|
24482
24637
|
interval = null;
|
|
24483
24638
|
frames = ["\u25D0", "\u25D3", "\u25D1", "\u25D2"];
|
|
24484
24639
|
i = 0;
|
|
24640
|
+
startedAt = 0;
|
|
24641
|
+
baseText = "";
|
|
24485
24642
|
start(text) {
|
|
24486
24643
|
this.stop();
|
|
24644
|
+
this.baseText = text;
|
|
24645
|
+
this.startedAt = Date.now();
|
|
24487
24646
|
this.interval = setInterval(() => {
|
|
24488
|
-
|
|
24647
|
+
const elapsedSec = Math.floor((Date.now() - this.startedAt) / 1e3);
|
|
24648
|
+
const timer = source_default.dim(` (${elapsedSec}s)`);
|
|
24649
|
+
const hint = elapsedSec >= 15 ? source_default.dim(" \xB7 still running, no output yet is normal for quiet commands") : "";
|
|
24650
|
+
process.stdout.write(`\r\x1B[K${source_default.cyan(this.frames[this.i % this.frames.length])} ${source_default.dim(this.baseText)}${timer}${hint}`);
|
|
24489
24651
|
this.i++;
|
|
24490
24652
|
}, 100);
|
|
24491
24653
|
}
|
|
@@ -24500,10 +24662,71 @@ var Spinner = class {
|
|
|
24500
24662
|
return this.interval !== null;
|
|
24501
24663
|
}
|
|
24502
24664
|
};
|
|
24665
|
+
var _mcpManager = null;
|
|
24666
|
+
var _mcpConfig = null;
|
|
24667
|
+
async function initMcp(workDir) {
|
|
24668
|
+
_mcpConfig = import_code_core3.McpManager.loadConfig(workDir);
|
|
24669
|
+
if (Object.keys(_mcpConfig.mcpServers).length === 0) {
|
|
24670
|
+
_mcpManager = null;
|
|
24671
|
+
return;
|
|
24672
|
+
}
|
|
24673
|
+
const manager = new import_code_core3.McpManager();
|
|
24674
|
+
await manager.connectAll(_mcpConfig);
|
|
24675
|
+
_mcpManager = manager;
|
|
24676
|
+
}
|
|
24677
|
+
function formatMcpStatus() {
|
|
24678
|
+
if (!_mcpConfig || Object.keys(_mcpConfig.mcpServers).length === 0) {
|
|
24679
|
+
return source_default.dim(" No MCP servers configured. Add one to .nexrall/mcp.json or ~/.nexrall/mcp.json.");
|
|
24680
|
+
}
|
|
24681
|
+
if (!_mcpManager)
|
|
24682
|
+
return source_default.dim(" MCP servers configured but not connected.");
|
|
24683
|
+
const rows = _mcpManager.getStatus();
|
|
24684
|
+
const lines = rows.map((s2) => {
|
|
24685
|
+
if (s2.connected) {
|
|
24686
|
+
return " " + source_default.green("\u25CF") + " " + source_default.bold(s2.name) + source_default.dim(` (${s2.transport}) \u2014 ${s2.tools.length} tool(s)`);
|
|
24687
|
+
}
|
|
24688
|
+
const authNote = s2.needsAuth ? source_default.yellow(" [needs OAuth \u2014 not supported in CLI yet, add a static Authorization header]") : "";
|
|
24689
|
+
return " " + source_default.red("\u25CF") + " " + source_default.bold(s2.name) + source_default.dim(` (${s2.transport}) \u2014 `) + source_default.red(s2.error ?? "failed to connect") + authNote;
|
|
24690
|
+
});
|
|
24691
|
+
return lines.join("\n");
|
|
24692
|
+
}
|
|
24693
|
+
function formatContextUsage(messages, modelAlias) {
|
|
24694
|
+
const window = (0, import_code_core3.contextWindowFor)(modelAlias);
|
|
24695
|
+
const tokens = (0, import_code_core3.estimateTokensRough)(messages);
|
|
24696
|
+
const bytes = (0, import_code_core3.estimateBodyBytes)(messages);
|
|
24697
|
+
const { prune, compact } = (0, import_code_core3.compactionThresholds)();
|
|
24698
|
+
const pct = Math.min(100, tokens / window * 100);
|
|
24699
|
+
const barWidth = 30;
|
|
24700
|
+
const filled = Math.round(pct / 100 * barWidth);
|
|
24701
|
+
const bar = "\u2588".repeat(filled) + "\u2591".repeat(barWidth - filled);
|
|
24702
|
+
const barColor = pct >= compact * 100 ? source_default.red : pct >= prune * 100 ? source_default.yellow : source_default.green;
|
|
24703
|
+
const lines = [
|
|
24704
|
+
"",
|
|
24705
|
+
" " + source_default.bold("Context usage"),
|
|
24706
|
+
" " + barColor(bar) + source_default.dim(` ~${pct.toFixed(1)}%`),
|
|
24707
|
+
source_default.dim(` ~${tokens.toLocaleString()} / ${window.toLocaleString()} tokens (rough estimate) \xB7 ${(bytes / 1024).toFixed(0)}KB serialized \xB7 ${messages.length} messages`),
|
|
24708
|
+
source_default.dim(` auto-prune at ~${(prune * 100).toFixed(0)}% \xB7 auto-compact (summarise) at ~${(compact * 100).toFixed(0)}%`),
|
|
24709
|
+
""
|
|
24710
|
+
];
|
|
24711
|
+
return lines.join("\n");
|
|
24712
|
+
}
|
|
24713
|
+
function formatAgentsList(workDir) {
|
|
24714
|
+
const types3 = (0, import_code_core3.loadAgentTypes)(workDir);
|
|
24715
|
+
if (!types3.length)
|
|
24716
|
+
return source_default.dim(" No agent types found (this should not happen \u2014 builtins always register).");
|
|
24717
|
+
const lines = types3.map((t2) => {
|
|
24718
|
+
const tools = t2.tools ? source_default.dim(` \u2014 tools: ${t2.tools.join(", ")}`) : source_default.dim(" \u2014 all tools");
|
|
24719
|
+
const model = t2.model ? source_default.dim(` \u2014 model: ${t2.model}`) : "";
|
|
24720
|
+
const scope = source_default.dim(` (${t2.source})`);
|
|
24721
|
+
return " " + source_default.cyan(t2.name.padEnd(16)) + source_default.white(t2.description) + scope + tools + model;
|
|
24722
|
+
});
|
|
24723
|
+
return lines.join("\n");
|
|
24724
|
+
}
|
|
24503
24725
|
async function runTurn(messages, modelAlias, workDir, abortSignal, env2, nexrallMd, mode, effort, checkpointManager, onProgress) {
|
|
24504
24726
|
let lastUsage;
|
|
24505
24727
|
const spinner = new Spinner();
|
|
24506
24728
|
const mdRender = new MarkdownStreamRenderer();
|
|
24729
|
+
const toolStream = new ToolStreamPrinter();
|
|
24507
24730
|
let toolStartTime = 0;
|
|
24508
24731
|
let lastToolName = "";
|
|
24509
24732
|
let thinkingTokens = 0;
|
|
@@ -24551,14 +24774,27 @@ async function runTurn(messages, modelAlias, workDir, abortSignal, env2, nexrall
|
|
|
24551
24774
|
return;
|
|
24552
24775
|
mdRender.flush();
|
|
24553
24776
|
spinner.stop();
|
|
24777
|
+
toolStream.reset();
|
|
24554
24778
|
process.stdout.write("\n");
|
|
24555
24779
|
console.log(formatToolUse(name, input));
|
|
24556
24780
|
lastToolName = name;
|
|
24557
24781
|
toolStartTime = Date.now();
|
|
24558
24782
|
spinner.start(`running ${name}\u2026`);
|
|
24559
24783
|
},
|
|
24784
|
+
// Live progress for foreground bash: the FIRST chunk stops the "running…"
|
|
24785
|
+
// spinner (which would otherwise overwrite/interleave badly with printed
|
|
24786
|
+
// lines) and every subsequent chunk streams straight to the terminal —
|
|
24787
|
+
// see ToolStreamPrinter for the line-buffering/cap logic.
|
|
24788
|
+
onToolStreamChunk: (_name, chunk) => {
|
|
24789
|
+
if (abortSignal.aborted)
|
|
24790
|
+
return;
|
|
24791
|
+
if (spinner.active)
|
|
24792
|
+
spinner.stop();
|
|
24793
|
+
toolStream.feed(chunk);
|
|
24794
|
+
},
|
|
24560
24795
|
onToolResult: (_name, res) => {
|
|
24561
24796
|
spinner.stop();
|
|
24797
|
+
toolStream.flush();
|
|
24562
24798
|
const durationMs = Date.now() - toolStartTime;
|
|
24563
24799
|
console.log(formatToolResult(lastToolName, res, durationMs));
|
|
24564
24800
|
toolStartTime = 0;
|
|
@@ -24610,7 +24846,8 @@ async function runTurn(messages, modelAlias, workDir, abortSignal, env2, nexrall
|
|
|
24610
24846
|
},
|
|
24611
24847
|
requestPermission,
|
|
24612
24848
|
checkpointManager,
|
|
24613
|
-
onProgress
|
|
24849
|
+
onProgress,
|
|
24850
|
+
mcpManager: _mcpManager ?? void 0
|
|
24614
24851
|
});
|
|
24615
24852
|
mdRender.flush();
|
|
24616
24853
|
spinner.stop();
|
|
@@ -24650,6 +24887,13 @@ async function runTurnHeadless(messages, modelAlias, workDir, _abortSignal, env2
|
|
|
24650
24887
|
onToolUse: (name, input) => {
|
|
24651
24888
|
emit({ type: "tool_use", tool: name, input });
|
|
24652
24889
|
},
|
|
24890
|
+
// Live bash progress for scripted/CI consumers — lets a wrapper tail a
|
|
24891
|
+
// long-running build/test command instead of blocking silently until
|
|
24892
|
+
// tool_result. Chunk is raw and un-truncated (unlike the final result,
|
|
24893
|
+
// which is head/tail-capped), so a chatty command can emit many of these.
|
|
24894
|
+
onToolStreamChunk: (name, chunk) => {
|
|
24895
|
+
emit({ type: "tool_stream", tool: name, chunk });
|
|
24896
|
+
},
|
|
24653
24897
|
onToolResult: (name, res) => {
|
|
24654
24898
|
toolCallCount++;
|
|
24655
24899
|
emit({ type: "tool_result", tool: name, ok: res.error === void 0, ...res.error ? { error: res.error } : {} });
|
|
@@ -24688,7 +24932,8 @@ async function runTurnHeadless(messages, modelAlias, workDir, _abortSignal, env2
|
|
|
24688
24932
|
return true;
|
|
24689
24933
|
},
|
|
24690
24934
|
checkpointManager,
|
|
24691
|
-
onProgress
|
|
24935
|
+
onProgress,
|
|
24936
|
+
mcpManager: _mcpManager ?? void 0
|
|
24692
24937
|
});
|
|
24693
24938
|
if (format === "json") {
|
|
24694
24939
|
process.stdout.write(JSON.stringify({
|
|
@@ -24723,8 +24968,12 @@ function printHelp() {
|
|
|
24723
24968
|
["/yolo", "Auto-approve all permissions"],
|
|
24724
24969
|
["/balance", "Show wallet balance"],
|
|
24725
24970
|
["/add <filepath>", "Add a file to conversation context"],
|
|
24971
|
+
["/image <filepath> [caption]", "Attach an image or PDF (png/jpg/gif/webp/pdf, max 10MB) and send it to the model"],
|
|
24726
24972
|
["/skills", "List skills (.nexrall/skills/<name>/SKILL.md or .nexrall/commands/*.md) \u2014 the model can also auto-invoke these"],
|
|
24727
24973
|
["/plugins", "List installed plugins (.nexrall/plugins/)"],
|
|
24974
|
+
["/mcp", "Show MCP server connection status"],
|
|
24975
|
+
["/agents", "List available sub-agent types (for the task tool)"],
|
|
24976
|
+
["/context", "Show context window usage for this conversation"],
|
|
24728
24977
|
["/update", "Update nex to the latest version"]
|
|
24729
24978
|
];
|
|
24730
24979
|
for (const [cmd, desc] of cmds) {
|
|
@@ -24785,6 +25034,15 @@ async function startChatSession(options) {
|
|
|
24785
25034
|
let skills = (0, import_code_core3.loadSkills)(workDir);
|
|
24786
25035
|
if (skills.length && !headless)
|
|
24787
25036
|
console.log(source_default.dim(` ${skills.length} skill(s) loaded`));
|
|
25037
|
+
try {
|
|
25038
|
+
await initMcp(workDir);
|
|
25039
|
+
const connected = _mcpManager?.serverNames.length ?? 0;
|
|
25040
|
+
const total = _mcpConfig ? Object.keys(_mcpConfig.mcpServers).length : 0;
|
|
25041
|
+
if (total && !headless) {
|
|
25042
|
+
console.log(source_default.dim(` ${connected}/${total} MCP server(s) connected`) + source_default.dim(" (/mcp for details)"));
|
|
25043
|
+
}
|
|
25044
|
+
} catch {
|
|
25045
|
+
}
|
|
24788
25046
|
if (headless && !options.prompt && !options.stdinText) {
|
|
24789
25047
|
process.stdout.write(JSON.stringify({ type: "error", error: "--output-format json/stream-json requires a one-shot prompt (or piped stdin)." }) + "\n");
|
|
24790
25048
|
process.exit(1);
|
|
@@ -24925,6 +25183,9 @@ ${text}` : "");
|
|
|
24925
25183
|
prompt: colors.primary.bold("> ")
|
|
24926
25184
|
});
|
|
24927
25185
|
setReadlineInterface(rl);
|
|
25186
|
+
enableBracketedPaste();
|
|
25187
|
+
process.on("exit", disableBracketedPaste);
|
|
25188
|
+
const uninstallPasteHandling = installPasteHandling(rl, process.stdin);
|
|
24928
25189
|
rl.prompt();
|
|
24929
25190
|
let inputBuffer = "";
|
|
24930
25191
|
rl.on("line", async (rawLine) => {
|
|
@@ -25283,6 +25544,80 @@ ${content}
|
|
|
25283
25544
|
rl.prompt();
|
|
25284
25545
|
return;
|
|
25285
25546
|
}
|
|
25547
|
+
case "/image": {
|
|
25548
|
+
if (agentRunning) {
|
|
25549
|
+
console.log(source_default.red(" Cannot attach while agent is running."));
|
|
25550
|
+
rl.prompt();
|
|
25551
|
+
return;
|
|
25552
|
+
}
|
|
25553
|
+
if (!arg) {
|
|
25554
|
+
console.log(source_default.red(" Usage: /image <filepath> [caption]"));
|
|
25555
|
+
rl.prompt();
|
|
25556
|
+
return;
|
|
25557
|
+
}
|
|
25558
|
+
const [rawPath, ...captionParts] = arg.split(/\s+/);
|
|
25559
|
+
const caption = captionParts.join(" ").trim();
|
|
25560
|
+
const filePath = path3.isAbsolute(rawPath) ? rawPath : path3.join(workDir, rawPath);
|
|
25561
|
+
const ext = path3.extname(filePath).toLowerCase();
|
|
25562
|
+
const IMAGE_MIME = {
|
|
25563
|
+
".png": "image/png",
|
|
25564
|
+
".jpg": "image/jpeg",
|
|
25565
|
+
".jpeg": "image/jpeg",
|
|
25566
|
+
".gif": "image/gif",
|
|
25567
|
+
".webp": "image/webp"
|
|
25568
|
+
};
|
|
25569
|
+
const isPdf = ext === ".pdf";
|
|
25570
|
+
const mimeType = IMAGE_MIME[ext];
|
|
25571
|
+
if (!mimeType && !isPdf) {
|
|
25572
|
+
console.log(source_default.red(` Unsupported file type: ${ext || "(none)"}. Supported: png, jpg, jpeg, gif, webp, pdf.`));
|
|
25573
|
+
rl.prompt();
|
|
25574
|
+
return;
|
|
25575
|
+
}
|
|
25576
|
+
let buf;
|
|
25577
|
+
try {
|
|
25578
|
+
buf = fs5.readFileSync(filePath);
|
|
25579
|
+
} catch (err) {
|
|
25580
|
+
console.error(source_default.red(" Failed: ") + String(err.message));
|
|
25581
|
+
rl.prompt();
|
|
25582
|
+
return;
|
|
25583
|
+
}
|
|
25584
|
+
const MAX_BYTES = 10 * 1024 * 1024;
|
|
25585
|
+
if (buf.length > MAX_BYTES) {
|
|
25586
|
+
console.log(source_default.red(` File too large (${(buf.length / 1024 / 1024).toFixed(1)}MB) \u2014 max 10MB.`));
|
|
25587
|
+
rl.prompt();
|
|
25588
|
+
return;
|
|
25589
|
+
}
|
|
25590
|
+
const rel = path3.relative(workDir, filePath);
|
|
25591
|
+
const data = buf.toString("base64");
|
|
25592
|
+
const label = caption ? `[Attached: ${rel}]
|
|
25593
|
+
${caption}` : `[Attached: ${rel}]`;
|
|
25594
|
+
const content = [{ type: "text", text: label }];
|
|
25595
|
+
content.push(
|
|
25596
|
+
isPdf ? { type: "document", source: { type: "base64", media_type: "application/pdf", data } } : { type: "image", source: { type: "base64", media_type: mimeType, data } }
|
|
25597
|
+
);
|
|
25598
|
+
console.log(source_default.dim(` Attached ${rel} (${(buf.length / 1024).toFixed(0)}KB) \u2014 sending\u2026`));
|
|
25599
|
+
checkpoints.beginTurn(`/image ${rel}${caption ? " " + caption : ""}`, messages.length);
|
|
25600
|
+
messages.push({ role: "user", content });
|
|
25601
|
+
rl.pause();
|
|
25602
|
+
abortSignal.aborted = false;
|
|
25603
|
+
agentRunning = true;
|
|
25604
|
+
try {
|
|
25605
|
+
const result = await runTurn(messages, modelAlias, workDir, abortSignal, env2, nexrallMd, agentMode, effortLevel, checkpoints, saveProgress);
|
|
25606
|
+
messages = result.messages;
|
|
25607
|
+
updateTitle();
|
|
25608
|
+
saveSession(sessionId, sessionTitle, workDir, messages);
|
|
25609
|
+
} catch (err) {
|
|
25610
|
+
messages = recoverTurn(err, messages);
|
|
25611
|
+
updateTitle();
|
|
25612
|
+
saveSession(sessionId, sessionTitle || "Untitled", workDir, messages);
|
|
25613
|
+
} finally {
|
|
25614
|
+
agentRunning = false;
|
|
25615
|
+
checkpoints.commitTurn();
|
|
25616
|
+
}
|
|
25617
|
+
rl.resume();
|
|
25618
|
+
rl.prompt();
|
|
25619
|
+
return;
|
|
25620
|
+
}
|
|
25286
25621
|
case "/update": {
|
|
25287
25622
|
rl.close();
|
|
25288
25623
|
await updateCommand({ yes: false });
|
|
@@ -25306,6 +25641,29 @@ ${content}
|
|
|
25306
25641
|
rl.prompt();
|
|
25307
25642
|
return;
|
|
25308
25643
|
}
|
|
25644
|
+
case "/mcp": {
|
|
25645
|
+
console.log();
|
|
25646
|
+
console.log(source_default.bold(" MCP servers:"));
|
|
25647
|
+
console.log(formatMcpStatus());
|
|
25648
|
+
console.log();
|
|
25649
|
+
rl.prompt();
|
|
25650
|
+
return;
|
|
25651
|
+
}
|
|
25652
|
+
case "/agents": {
|
|
25653
|
+
console.log();
|
|
25654
|
+
console.log(source_default.bold(" Sub-agent types (used by the `task` tool):"));
|
|
25655
|
+
console.log(formatAgentsList(workDir));
|
|
25656
|
+
console.log();
|
|
25657
|
+
console.log(source_default.dim(" Define your own in .nexrall/agents/<name>.md or ~/.nexrall/agents/<name>.md"));
|
|
25658
|
+
console.log();
|
|
25659
|
+
rl.prompt();
|
|
25660
|
+
return;
|
|
25661
|
+
}
|
|
25662
|
+
case "/context": {
|
|
25663
|
+
console.log(formatContextUsage(messages, modelAlias));
|
|
25664
|
+
rl.prompt();
|
|
25665
|
+
return;
|
|
25666
|
+
}
|
|
25309
25667
|
case "/skills":
|
|
25310
25668
|
case "/commands": {
|
|
25311
25669
|
skills = (0, import_code_core3.loadSkills)(workDir);
|
|
@@ -25383,6 +25741,7 @@ ${content}
|
|
|
25383
25741
|
rl.prompt();
|
|
25384
25742
|
});
|
|
25385
25743
|
rl.on("close", () => {
|
|
25744
|
+
uninstallPasteHandling();
|
|
25386
25745
|
updateTitle();
|
|
25387
25746
|
if (messages.length)
|
|
25388
25747
|
saveSession(sessionId, sessionTitle || "Untitled", workDir, messages);
|
|
@@ -25596,7 +25955,7 @@ function pluginListCommand() {
|
|
|
25596
25955
|
|
|
25597
25956
|
// src/index.ts
|
|
25598
25957
|
var program2 = new Command();
|
|
25599
|
-
program2.name("nex").description("Nexrall Code \u2014 AI coding assistant (powered by Nexrall)").version("0.5.
|
|
25958
|
+
program2.name("nex").description("Nexrall Code \u2014 AI coding assistant (powered by Nexrall)").version("0.5.27");
|
|
25600
25959
|
program2.command("auth").description("Login to your Nexrall account").action(authCommand);
|
|
25601
25960
|
program2.command("logout").description("Log out of your Nexrall account").action(logoutCommand);
|
|
25602
25961
|
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.27",
|
|
4
4
|
"description": "Nexrall Code — AI coding assistant for your terminal (headless agent for scripts, CI and automation)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"ora": "^8.0.1",
|
|
38
38
|
"prompts": "^2.4.2",
|
|
39
39
|
"readline": "^1.3.0",
|
|
40
|
-
"@nexrall/code-core": "1.4.
|
|
40
|
+
"@nexrall/code-core": "1.4.21"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@aws-sdk/client-s3": "^3.600.0",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"build": "node build.js",
|
|
53
53
|
"dev": "tsx src/index.ts",
|
|
54
54
|
"start": "node dist/index.js",
|
|
55
|
+
"test": "tsc --noEmit && tsc --noEmit -p test/tsconfig.json && node --import tsx --test test/*.test.ts test/*.test.mts",
|
|
55
56
|
"release": "node build.js && node scripts/upload-release.js"
|
|
56
57
|
}
|
|
57
58
|
}
|