nexrall-code 0.5.24 → 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 +163 -5
- 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,
|
|
@@ -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 {
|
|
@@ -23468,6 +23469,77 @@ function formatUsage(outputTokens) {
|
|
|
23468
23469
|
return source_default.dim(`\u2193 ${tok} tokens`);
|
|
23469
23470
|
}
|
|
23470
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
|
+
|
|
23471
23543
|
// src/permissions/handler.ts
|
|
23472
23544
|
var readline2 = __toESM(require("readline"));
|
|
23473
23545
|
var fs2 = __toESM(require("fs"));
|
|
@@ -24249,7 +24321,7 @@ async function requestPermission(req) {
|
|
|
24249
24321
|
var fs3 = __toESM(require("fs"));
|
|
24250
24322
|
var path = __toESM(require("path"));
|
|
24251
24323
|
var os2 = __toESM(require("os"));
|
|
24252
|
-
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");
|
|
24253
24325
|
function ensureDir() {
|
|
24254
24326
|
fs3.mkdirSync(SESSIONS_DIR, { recursive: true });
|
|
24255
24327
|
}
|
|
@@ -24565,10 +24637,17 @@ var Spinner = class {
|
|
|
24565
24637
|
interval = null;
|
|
24566
24638
|
frames = ["\u25D0", "\u25D3", "\u25D1", "\u25D2"];
|
|
24567
24639
|
i = 0;
|
|
24640
|
+
startedAt = 0;
|
|
24641
|
+
baseText = "";
|
|
24568
24642
|
start(text) {
|
|
24569
24643
|
this.stop();
|
|
24644
|
+
this.baseText = text;
|
|
24645
|
+
this.startedAt = Date.now();
|
|
24570
24646
|
this.interval = setInterval(() => {
|
|
24571
|
-
|
|
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}`);
|
|
24572
24651
|
this.i++;
|
|
24573
24652
|
}, 100);
|
|
24574
24653
|
}
|
|
@@ -24889,6 +24968,7 @@ function printHelp() {
|
|
|
24889
24968
|
["/yolo", "Auto-approve all permissions"],
|
|
24890
24969
|
["/balance", "Show wallet balance"],
|
|
24891
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"],
|
|
24892
24972
|
["/skills", "List skills (.nexrall/skills/<name>/SKILL.md or .nexrall/commands/*.md) \u2014 the model can also auto-invoke these"],
|
|
24893
24973
|
["/plugins", "List installed plugins (.nexrall/plugins/)"],
|
|
24894
24974
|
["/mcp", "Show MCP server connection status"],
|
|
@@ -25103,6 +25183,9 @@ ${text}` : "");
|
|
|
25103
25183
|
prompt: colors.primary.bold("> ")
|
|
25104
25184
|
});
|
|
25105
25185
|
setReadlineInterface(rl);
|
|
25186
|
+
enableBracketedPaste();
|
|
25187
|
+
process.on("exit", disableBracketedPaste);
|
|
25188
|
+
const uninstallPasteHandling = installPasteHandling(rl, process.stdin);
|
|
25106
25189
|
rl.prompt();
|
|
25107
25190
|
let inputBuffer = "";
|
|
25108
25191
|
rl.on("line", async (rawLine) => {
|
|
@@ -25461,6 +25544,80 @@ ${content}
|
|
|
25461
25544
|
rl.prompt();
|
|
25462
25545
|
return;
|
|
25463
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
|
+
}
|
|
25464
25621
|
case "/update": {
|
|
25465
25622
|
rl.close();
|
|
25466
25623
|
await updateCommand({ yes: false });
|
|
@@ -25584,6 +25741,7 @@ ${content}
|
|
|
25584
25741
|
rl.prompt();
|
|
25585
25742
|
});
|
|
25586
25743
|
rl.on("close", () => {
|
|
25744
|
+
uninstallPasteHandling();
|
|
25587
25745
|
updateTitle();
|
|
25588
25746
|
if (messages.length)
|
|
25589
25747
|
saveSession(sessionId, sessionTitle || "Untitled", workDir, messages);
|
|
@@ -25797,7 +25955,7 @@ function pluginListCommand() {
|
|
|
25797
25955
|
|
|
25798
25956
|
// src/index.ts
|
|
25799
25957
|
var program2 = new Command();
|
|
25800
|
-
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");
|
|
25801
25959
|
program2.command("auth").description("Login to your Nexrall account").action(authCommand);
|
|
25802
25960
|
program2.command("logout").description("Log out of your Nexrall account").action(logoutCommand);
|
|
25803
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
|
}
|