nexrall-code 0.5.62 → 0.5.63
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 +117 -144
- package/install.ps1 +25 -59
- package/install.sh +34 -98
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -3160,8 +3160,8 @@ var require_auth = __commonJS({
|
|
|
3160
3160
|
exports.updateTokens = updateTokens;
|
|
3161
3161
|
var fs9 = __importStar(__require("fs"));
|
|
3162
3162
|
var path6 = __importStar(__require("path"));
|
|
3163
|
-
var
|
|
3164
|
-
var CONFIG_DIR = path6.join(
|
|
3163
|
+
var os5 = __importStar(__require("os"));
|
|
3164
|
+
var CONFIG_DIR = path6.join(os5.homedir(), ".nexrall");
|
|
3165
3165
|
var CONFIG_FILE = path6.join(CONFIG_DIR, "config.json");
|
|
3166
3166
|
function ensureConfigDir() {
|
|
3167
3167
|
if (!fs9.existsSync(CONFIG_DIR)) {
|
|
@@ -10677,7 +10677,7 @@ var require_sandbox = __commonJS({
|
|
|
10677
10677
|
exports.parseSandboxConfig = parseSandboxConfig;
|
|
10678
10678
|
exports.wrapCommandForSandbox = wrapCommandForSandbox;
|
|
10679
10679
|
var child_process_1 = __require("child_process");
|
|
10680
|
-
var
|
|
10680
|
+
var os5 = __importStar(__require("os"));
|
|
10681
10681
|
function parseSandboxConfig(raw) {
|
|
10682
10682
|
if (raw === void 0 || raw === null || raw === false || raw === "off")
|
|
10683
10683
|
return null;
|
|
@@ -10722,9 +10722,9 @@ var require_sandbox = __commonJS({
|
|
|
10722
10722
|
return lines.join("\n");
|
|
10723
10723
|
}
|
|
10724
10724
|
function wrapCommandForSandbox(command, workDir, cfg) {
|
|
10725
|
-
const platform3 =
|
|
10725
|
+
const platform3 = os5.platform();
|
|
10726
10726
|
if (platform3 === "darwin") {
|
|
10727
|
-
const writePaths = Array.from(/* @__PURE__ */ new Set([workDir, "/tmp", "/private/tmp", "/private/var/folders",
|
|
10727
|
+
const writePaths = Array.from(/* @__PURE__ */ new Set([workDir, "/tmp", "/private/tmp", "/private/var/folders", os5.tmpdir(), ...cfg.writePaths]));
|
|
10728
10728
|
const profile = buildSeatbeltProfile(writePaths, cfg.network);
|
|
10729
10729
|
return {
|
|
10730
10730
|
command: `sandbox-exec -p ${shQuote(profile)} /bin/sh -c ${shQuote(command)}`,
|
|
@@ -11026,10 +11026,10 @@ var require_memory = __commonJS({
|
|
|
11026
11026
|
exports.agentMemoryPreamble = agentMemoryPreamble;
|
|
11027
11027
|
exports.compactMemoryIfNeeded = compactMemoryIfNeeded2;
|
|
11028
11028
|
var fs9 = __importStar(__require("fs"));
|
|
11029
|
-
var
|
|
11029
|
+
var os5 = __importStar(__require("os"));
|
|
11030
11030
|
var path6 = __importStar(__require("path"));
|
|
11031
11031
|
var crypto2 = __importStar(__require("crypto"));
|
|
11032
|
-
var MEMORY_ROOT = process.env.NEXRALL_MEMORY_DIR || path6.join(
|
|
11032
|
+
var MEMORY_ROOT = process.env.NEXRALL_MEMORY_DIR || path6.join(os5.homedir(), ".nexrall", "memory");
|
|
11033
11033
|
var GLOBAL_FILE = path6.join(MEMORY_ROOT, "global.md");
|
|
11034
11034
|
function memoryFilePath(scope, workDir) {
|
|
11035
11035
|
if (scope === "global" || !workDir)
|
|
@@ -11285,7 +11285,7 @@ var require_plugins = __commonJS({
|
|
|
11285
11285
|
exports.pluginMcpServers = pluginMcpServers;
|
|
11286
11286
|
var fs9 = __importStar(__require("fs"));
|
|
11287
11287
|
var path6 = __importStar(__require("path"));
|
|
11288
|
-
var
|
|
11288
|
+
var os5 = __importStar(__require("os"));
|
|
11289
11289
|
exports.FILE_CANDIDATES = {
|
|
11290
11290
|
manifest: ["plugin.json", path6.join(".claude-plugin", "plugin.json")],
|
|
11291
11291
|
hooks: ["hooks.json", path6.join("hooks", "hooks.json")],
|
|
@@ -11345,7 +11345,7 @@ var require_plugins = __commonJS({
|
|
|
11345
11345
|
function loadPlugins3(workDir) {
|
|
11346
11346
|
const out = /* @__PURE__ */ new Map();
|
|
11347
11347
|
scanRoot(path6.join(workDir, ".nexrall", "plugins"), "project", out);
|
|
11348
|
-
scanRoot(path6.join(
|
|
11348
|
+
scanRoot(path6.join(os5.homedir(), ".nexrall", "plugins"), "global", out);
|
|
11349
11349
|
return [...out.values()];
|
|
11350
11350
|
}
|
|
11351
11351
|
function pluginAssetDirs(workDir, kind) {
|
|
@@ -11454,7 +11454,7 @@ var require_loader = __commonJS({
|
|
|
11454
11454
|
exports.expandCommand = expandCommand;
|
|
11455
11455
|
var fs9 = __importStar(__require("fs"));
|
|
11456
11456
|
var path6 = __importStar(__require("path"));
|
|
11457
|
-
var
|
|
11457
|
+
var os5 = __importStar(__require("os"));
|
|
11458
11458
|
var child_process_1 = __require("child_process");
|
|
11459
11459
|
var index_1 = require_plugins();
|
|
11460
11460
|
var BUILTIN_COMMANDS = [
|
|
@@ -11535,7 +11535,7 @@ var require_loader = __commonJS({
|
|
|
11535
11535
|
function loadSlashCommands(workDir) {
|
|
11536
11536
|
const out = /* @__PURE__ */ new Map();
|
|
11537
11537
|
loadDir(path6.join(workDir, ".nexrall", "commands"), "project", out);
|
|
11538
|
-
loadDir(path6.join(
|
|
11538
|
+
loadDir(path6.join(os5.homedir(), ".nexrall", "commands"), "global", out);
|
|
11539
11539
|
for (const dir of (0, index_1.pluginAssetDirs)(workDir, "commands"))
|
|
11540
11540
|
loadDir(dir, "plugin", out);
|
|
11541
11541
|
for (const cmd of BUILTIN_COMMANDS) {
|
|
@@ -11647,7 +11647,7 @@ var require_skills = __commonJS({
|
|
|
11647
11647
|
exports.expandSkill = expandSkill2;
|
|
11648
11648
|
var fs9 = __importStar(__require("fs"));
|
|
11649
11649
|
var path6 = __importStar(__require("path"));
|
|
11650
|
-
var
|
|
11650
|
+
var os5 = __importStar(__require("os"));
|
|
11651
11651
|
var index_1 = require_plugins();
|
|
11652
11652
|
var loader_1 = require_loader();
|
|
11653
11653
|
function parseFrontmatter(raw) {
|
|
@@ -11778,8 +11778,8 @@ var require_skills = __commonJS({
|
|
|
11778
11778
|
const out = /* @__PURE__ */ new Map();
|
|
11779
11779
|
loadFlatCommandDir(path6.join(workDir, ".nexrall", "commands"), "project", out);
|
|
11780
11780
|
loadSkillDir(path6.join(workDir, ".nexrall", "skills"), "project", out);
|
|
11781
|
-
loadFlatCommandDir(path6.join(
|
|
11782
|
-
loadSkillDir(path6.join(
|
|
11781
|
+
loadFlatCommandDir(path6.join(os5.homedir(), ".nexrall", "commands"), "global", out);
|
|
11782
|
+
loadSkillDir(path6.join(os5.homedir(), ".nexrall", "skills"), "global", out);
|
|
11783
11783
|
for (const dir of (0, index_1.pluginAssetDirs)(workDir, "commands"))
|
|
11784
11784
|
loadFlatCommandDir(dir, "plugin", out);
|
|
11785
11785
|
for (const dir of (0, index_1.pluginAssetDirs)(workDir, "skills"))
|
|
@@ -12743,7 +12743,7 @@ var require_executor = __commonJS({
|
|
|
12743
12743
|
exports.executeTool = executeTool;
|
|
12744
12744
|
var fs9 = __importStar(__require("fs"));
|
|
12745
12745
|
var path6 = __importStar(__require("path"));
|
|
12746
|
-
var
|
|
12746
|
+
var os5 = __importStar(__require("os"));
|
|
12747
12747
|
var https3 = __importStar(__require("https"));
|
|
12748
12748
|
var http3 = __importStar(__require("http"));
|
|
12749
12749
|
var dns = __importStar(__require("dns"));
|
|
@@ -12769,7 +12769,7 @@ var require_executor = __commonJS({
|
|
|
12769
12769
|
var READ_CHARS_PER_TOKEN = 4;
|
|
12770
12770
|
var MAX_READ_CHARS = MAX_READ_TOKENS * READ_CHARS_PER_TOKEN;
|
|
12771
12771
|
var MAX_SPILL_BYTES = 20 * 1024 * 1024;
|
|
12772
|
-
var SPILL_DIR = path6.join(
|
|
12772
|
+
var SPILL_DIR = path6.join(os5.tmpdir(), "nexrall-code", "bash-output");
|
|
12773
12773
|
var BLOCKED_REGEXES = [
|
|
12774
12774
|
// Filesystem destruction — match rm/chmod with any whitespace between flags.
|
|
12775
12775
|
// Only root itself and BARE top-level system dirs are blocked; ordinary
|
|
@@ -13919,6 +13919,19 @@ ${diff3}${xfile}${sec}` };
|
|
|
13919
13919
|
return false;
|
|
13920
13920
|
return m2.slice(1).every((o) => Number(o) <= 255);
|
|
13921
13921
|
}
|
|
13922
|
+
function fetchBlocklistCheck(parsedUrl) {
|
|
13923
|
+
const raw = process.env.NEXRALL_FETCH_BLOCKLIST;
|
|
13924
|
+
if (!raw)
|
|
13925
|
+
return null;
|
|
13926
|
+
const host = parsedUrl.hostname.toLowerCase().replace(/^\[|\]$/g, "");
|
|
13927
|
+
const entries = raw.split(",").map((s2) => s2.trim().toLowerCase()).filter(Boolean);
|
|
13928
|
+
for (const entry of entries) {
|
|
13929
|
+
if (host === entry || host.endsWith(`.${entry}`)) {
|
|
13930
|
+
return `Refusing to fetch "${host}" \u2014 blocked by NEXRALL_FETCH_BLOCKLIST (matched "${entry}").`;
|
|
13931
|
+
}
|
|
13932
|
+
}
|
|
13933
|
+
return null;
|
|
13934
|
+
}
|
|
13922
13935
|
async function fetchUrl(input, _workDir2, _redirectCount = 0) {
|
|
13923
13936
|
const url = typeof input.url === "string" ? input.url : "";
|
|
13924
13937
|
if (!url)
|
|
@@ -13935,6 +13948,9 @@ ${diff3}${xfile}${sec}` };
|
|
|
13935
13948
|
if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
|
|
13936
13949
|
return { error: `Unsupported protocol: ${parsedUrl.protocol}. Only http and https are supported.` };
|
|
13937
13950
|
}
|
|
13951
|
+
const blocklistError = fetchBlocklistCheck(parsedUrl);
|
|
13952
|
+
if (blocklistError)
|
|
13953
|
+
return { error: blocklistError };
|
|
13938
13954
|
const ssrfError = await ssrfCheck(parsedUrl);
|
|
13939
13955
|
if (ssrfError)
|
|
13940
13956
|
return { error: ssrfError };
|
|
@@ -14682,7 +14698,7 @@ var require_agentTypes = __commonJS({
|
|
|
14682
14698
|
exports.findAgentType = findAgentType;
|
|
14683
14699
|
var fs9 = __importStar(__require("fs"));
|
|
14684
14700
|
var path6 = __importStar(__require("path"));
|
|
14685
|
-
var
|
|
14701
|
+
var os5 = __importStar(__require("os"));
|
|
14686
14702
|
var index_1 = require_plugins();
|
|
14687
14703
|
var VALID_MEMORY_SCOPES = ["project", "user", "local"];
|
|
14688
14704
|
function parseMemoryScope(v) {
|
|
@@ -15167,7 +15183,7 @@ var require_agentTypes = __commonJS({
|
|
|
15167
15183
|
const out = /* @__PURE__ */ new Map();
|
|
15168
15184
|
const warnings = [];
|
|
15169
15185
|
loadDir(path6.join(workDir, ".nexrall", "agents"), "project", out, warnings);
|
|
15170
|
-
loadDir(path6.join(
|
|
15186
|
+
loadDir(path6.join(os5.homedir(), ".nexrall", "agents"), "global", out, warnings);
|
|
15171
15187
|
for (const dir of (0, index_1.pluginAssetDirs)(workDir, "agents"))
|
|
15172
15188
|
loadDir(dir, "plugin", out, warnings);
|
|
15173
15189
|
for (const agent of BUILTIN_AGENTS) {
|
|
@@ -15275,7 +15291,7 @@ var require_rules = __commonJS({
|
|
|
15275
15291
|
exports.evaluatePermission = evaluatePermission2;
|
|
15276
15292
|
var fs9 = __importStar(__require("fs"));
|
|
15277
15293
|
var path6 = __importStar(__require("path"));
|
|
15278
|
-
var
|
|
15294
|
+
var os5 = __importStar(__require("os"));
|
|
15279
15295
|
function managedSettingsPath() {
|
|
15280
15296
|
if (process.platform === "darwin")
|
|
15281
15297
|
return "/Library/Application Support/Nexrall/managed-settings.json";
|
|
@@ -15298,7 +15314,7 @@ var require_rules = __commonJS({
|
|
|
15298
15314
|
function loadSettings2(workDir) {
|
|
15299
15315
|
const tiers = [
|
|
15300
15316
|
managedSettingsPath(),
|
|
15301
|
-
path6.join(
|
|
15317
|
+
path6.join(os5.homedir(), ".nexrall", "settings.json"),
|
|
15302
15318
|
path6.join(workDir, ".nexrall", "settings.json"),
|
|
15303
15319
|
path6.join(workDir, ".nexrall", "settings.local.json")
|
|
15304
15320
|
];
|
|
@@ -16879,7 +16895,15 @@ ${partial}` : "",
|
|
|
16879
16895
|
"gpt-5.4": 922e3,
|
|
16880
16896
|
"gpt-5.4-mini": 272e3,
|
|
16881
16897
|
"gpt-4.1": 1047576,
|
|
16882
|
-
"gpt-4o-mini": 128e3
|
|
16898
|
+
"gpt-4o-mini": 128e3,
|
|
16899
|
+
// DeepSeek, by real model id (documented — see backend/services/providers/
|
|
16900
|
+
// modelRegistry.js's own TODO(unverified-by-400): DeepSeek accepts an
|
|
16901
|
+
// oversized max_completion_tokens without rejecting it, so there was no 400
|
|
16902
|
+
// to measure the ceiling from the way the OpenAI rows above were).
|
|
16903
|
+
"deepseek-v4-pro": 1048576,
|
|
16904
|
+
"deepseek-v4-flash": 1048576,
|
|
16905
|
+
// Qwen (DashScope), by real model id (documented max input, same caveat).
|
|
16906
|
+
"qwen3.7-max": 991800
|
|
16883
16907
|
};
|
|
16884
16908
|
function contextWindowFor2(model) {
|
|
16885
16909
|
return MODEL_CONTEXT_TOKENS[model ?? "turbo"] ?? 128e3;
|
|
@@ -18268,7 +18292,7 @@ var require_manager = __commonJS({
|
|
|
18268
18292
|
exports.McpManager = void 0;
|
|
18269
18293
|
var fs9 = __importStar(__require("fs"));
|
|
18270
18294
|
var path6 = __importStar(__require("path"));
|
|
18271
|
-
var
|
|
18295
|
+
var os5 = __importStar(__require("os"));
|
|
18272
18296
|
var client_1 = require_client2();
|
|
18273
18297
|
var httpClient_1 = require_httpClient();
|
|
18274
18298
|
var sseClient_1 = require_sseClient();
|
|
@@ -18296,7 +18320,7 @@ var require_manager = __commonJS({
|
|
|
18296
18320
|
} catch {
|
|
18297
18321
|
}
|
|
18298
18322
|
const locations = [
|
|
18299
|
-
path6.join(
|
|
18323
|
+
path6.join(os5.homedir(), ".nexrall", "mcp.json"),
|
|
18300
18324
|
path6.join(workDir, ".nexrall", "mcp.json")
|
|
18301
18325
|
];
|
|
18302
18326
|
for (const loc of locations) {
|
|
@@ -18401,7 +18425,7 @@ var require_manager = __commonJS({
|
|
|
18401
18425
|
// ─── Config file persistence (for the management UI) ──────────────────────────
|
|
18402
18426
|
/** Path to an mcp.json for the given scope. */
|
|
18403
18427
|
static configPath(workDir, scope) {
|
|
18404
|
-
return scope === "user" ? path6.join(
|
|
18428
|
+
return scope === "user" ? path6.join(os5.homedir(), ".nexrall", "mcp.json") : path6.join(workDir, ".nexrall", "mcp.json");
|
|
18405
18429
|
}
|
|
18406
18430
|
static readConfigFile(p) {
|
|
18407
18431
|
try {
|
|
@@ -18503,7 +18527,7 @@ var require_manager2 = __commonJS({
|
|
|
18503
18527
|
exports.isMutatingTool = isMutatingTool;
|
|
18504
18528
|
exports.isPotentiallyMutatingBash = isPotentiallyMutatingBash;
|
|
18505
18529
|
var fs9 = __importStar(__require("fs"));
|
|
18506
|
-
var
|
|
18530
|
+
var os5 = __importStar(__require("os"));
|
|
18507
18531
|
var path6 = __importStar(__require("path"));
|
|
18508
18532
|
var crypto2 = __importStar(__require("crypto"));
|
|
18509
18533
|
var child_process_1 = __require("child_process");
|
|
@@ -18562,7 +18586,7 @@ var require_manager2 = __commonJS({
|
|
|
18562
18586
|
this.current = null;
|
|
18563
18587
|
this.nextId = 1;
|
|
18564
18588
|
const key = crypto2.createHash("sha1").update(path6.resolve(workDir) + "\0" + (scope ?? "")).digest("hex").slice(0, 16);
|
|
18565
|
-
const base = process.env.NEXRALL_CHECKPOINT_DIR || path6.join(
|
|
18589
|
+
const base = process.env.NEXRALL_CHECKPOINT_DIR || path6.join(os5.homedir(), ".nexrall", "checkpoints");
|
|
18566
18590
|
this.storeDir = path6.join(base, key);
|
|
18567
18591
|
this.loadFromDisk();
|
|
18568
18592
|
}
|
|
@@ -19168,7 +19192,7 @@ var require_sources = __commonJS({
|
|
|
19168
19192
|
exports.sourcesFileFor = sourcesFileFor2;
|
|
19169
19193
|
var fs9 = __importStar(__require("fs"));
|
|
19170
19194
|
var path6 = __importStar(__require("path"));
|
|
19171
|
-
var
|
|
19195
|
+
var os5 = __importStar(__require("os"));
|
|
19172
19196
|
function managedSettingsPath() {
|
|
19173
19197
|
if (process.platform === "darwin")
|
|
19174
19198
|
return "/Library/Application Support/Nexrall/managed-settings.json";
|
|
@@ -19219,7 +19243,7 @@ var require_sources = __commonJS({
|
|
|
19219
19243
|
function loadDeclaredSources2(workDir, opts = {}) {
|
|
19220
19244
|
const out = /* @__PURE__ */ new Map();
|
|
19221
19245
|
collect(managedSettingsPath(), "managed", out);
|
|
19222
|
-
collect(path6.join(
|
|
19246
|
+
collect(path6.join(os5.homedir(), ".nexrall", "settings.json"), "user", out);
|
|
19223
19247
|
if (opts.includeProject) {
|
|
19224
19248
|
collect(path6.join(workDir, ".nexrall", "settings.json"), "project", out);
|
|
19225
19249
|
collect(path6.join(workDir, ".nexrall", "settings.local.json"), "project", out);
|
|
@@ -19274,7 +19298,7 @@ var require_sources = __commonJS({
|
|
|
19274
19298
|
return true;
|
|
19275
19299
|
}
|
|
19276
19300
|
function sourcesFileFor2(scope, workDir) {
|
|
19277
|
-
return scope === "user" ? path6.join(
|
|
19301
|
+
return scope === "user" ? path6.join(os5.homedir(), ".nexrall", "settings.json") : path6.join(workDir, ".nexrall", "settings.json");
|
|
19278
19302
|
}
|
|
19279
19303
|
}
|
|
19280
19304
|
});
|
|
@@ -19339,7 +19363,7 @@ var require_installer = __commonJS({
|
|
|
19339
19363
|
exports.updatePlugin = updatePlugin2;
|
|
19340
19364
|
var fs9 = __importStar(__require("fs"));
|
|
19341
19365
|
var path6 = __importStar(__require("path"));
|
|
19342
|
-
var
|
|
19366
|
+
var os5 = __importStar(__require("os"));
|
|
19343
19367
|
var child_process_1 = __require("child_process");
|
|
19344
19368
|
var client_1 = require_client();
|
|
19345
19369
|
var index_1 = require_plugins();
|
|
@@ -19378,7 +19402,7 @@ var require_installer = __commonJS({
|
|
|
19378
19402
|
if (!raw)
|
|
19379
19403
|
throw new Error("Empty plugin source.");
|
|
19380
19404
|
if (raw.startsWith("./") || raw.startsWith("../") || raw.startsWith("/") || raw.startsWith("~/")) {
|
|
19381
|
-
const abs = path6.resolve(raw.replace(/^~(?=\/)/,
|
|
19405
|
+
const abs = path6.resolve(raw.replace(/^~(?=\/)/, os5.homedir()));
|
|
19382
19406
|
return { kind: "local", repo: abs, raw };
|
|
19383
19407
|
}
|
|
19384
19408
|
let rest = raw;
|
|
@@ -19506,7 +19530,7 @@ var require_installer = __commonJS({
|
|
|
19506
19530
|
}
|
|
19507
19531
|
}
|
|
19508
19532
|
function pluginsRoot(scope, workDir) {
|
|
19509
|
-
return scope === "project" ? path6.join(workDir || process.cwd(), ".nexrall", "plugins") : path6.join(
|
|
19533
|
+
return scope === "project" ? path6.join(workDir || process.cwd(), ".nexrall", "plugins") : path6.join(os5.homedir(), ".nexrall", "plugins");
|
|
19510
19534
|
}
|
|
19511
19535
|
async function installPlugin2(spec, opts = {}) {
|
|
19512
19536
|
const source2 = parsePluginSource2(spec);
|
|
@@ -19515,7 +19539,7 @@ var require_installer = __commonJS({
|
|
|
19515
19539
|
if (patterns && source2.kind === "github" && !(0, sources_1.isSourceAllowed)(source2.raw, patterns)) {
|
|
19516
19540
|
throw new Error(`Blocked by your organisation's policy: plugins may only be installed from ${patterns.join(", ")}.`);
|
|
19517
19541
|
}
|
|
19518
|
-
const tmpBase = fs9.mkdtempSync(path6.join(
|
|
19542
|
+
const tmpBase = fs9.mkdtempSync(path6.join(os5.tmpdir(), "nexrall-plugin-"));
|
|
19519
19543
|
try {
|
|
19520
19544
|
let repoRoot;
|
|
19521
19545
|
if (source2.kind === "local") {
|
|
@@ -54131,7 +54155,7 @@ function stopSpinner(handle2) {
|
|
|
54131
54155
|
import * as readline3 from "readline";
|
|
54132
54156
|
import * as path4 from "path";
|
|
54133
54157
|
import * as fs8 from "fs";
|
|
54134
|
-
import * as
|
|
54158
|
+
import * as os4 from "os";
|
|
54135
54159
|
import * as crypto from "crypto";
|
|
54136
54160
|
import { execSync } from "child_process";
|
|
54137
54161
|
var import_code_core3 = __toESM(require_dist2(), 1);
|
|
@@ -55385,51 +55409,28 @@ function lastSession() {
|
|
|
55385
55409
|
import * as fs4 from "fs";
|
|
55386
55410
|
import * as https2 from "https";
|
|
55387
55411
|
import * as path2 from "path";
|
|
55388
|
-
import
|
|
55389
|
-
var
|
|
55390
|
-
var
|
|
55412
|
+
import { fileURLToPath } from "url";
|
|
55413
|
+
var __dirname = path2.dirname(fileURLToPath(import.meta.url));
|
|
55414
|
+
var NPM_REGISTRY_LATEST = "https://registry.npmjs.org/nexrall-code/latest";
|
|
55391
55415
|
function get2(url) {
|
|
55392
55416
|
return new Promise((resolve3, reject) => {
|
|
55393
|
-
https2.get(url, { headers: { "User-Agent": "nexrall-cli-updater" } }, (res) => {
|
|
55417
|
+
https2.get(url, { headers: { "User-Agent": "nexrall-cli-updater", Accept: "application/json" } }, (res) => {
|
|
55394
55418
|
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
55395
55419
|
return get2(res.headers.location).then(resolve3).catch(reject);
|
|
55396
55420
|
}
|
|
55421
|
+
if (res.statusCode !== 200) {
|
|
55422
|
+
res.resume();
|
|
55423
|
+
return reject(new Error(`npm registry returned HTTP ${res.statusCode}`));
|
|
55424
|
+
}
|
|
55397
55425
|
let raw = "";
|
|
55398
55426
|
res.on("data", (c) => raw += c.toString());
|
|
55399
55427
|
res.on("end", () => resolve3(raw));
|
|
55400
55428
|
}).on("error", reject);
|
|
55401
55429
|
});
|
|
55402
55430
|
}
|
|
55403
|
-
function download(url, dest) {
|
|
55404
|
-
return new Promise((resolve3, reject) => {
|
|
55405
|
-
const doGet = (u) => {
|
|
55406
|
-
https2.get(u, { headers: { "User-Agent": "nexrall-cli-updater" } }, (res) => {
|
|
55407
|
-
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
55408
|
-
return doGet(res.headers.location);
|
|
55409
|
-
}
|
|
55410
|
-
if (res.statusCode !== 200) {
|
|
55411
|
-
return reject(new Error(`Download failed: HTTP ${res.statusCode}`));
|
|
55412
|
-
}
|
|
55413
|
-
const tmpPath = dest + ".tmp";
|
|
55414
|
-
const file = fs4.createWriteStream(tmpPath);
|
|
55415
|
-
res.pipe(file);
|
|
55416
|
-
file.on("finish", () => {
|
|
55417
|
-
file.close();
|
|
55418
|
-
fs4.renameSync(tmpPath, dest);
|
|
55419
|
-
resolve3();
|
|
55420
|
-
});
|
|
55421
|
-
file.on("error", (err) => {
|
|
55422
|
-
fs4.unlinkSync(tmpPath);
|
|
55423
|
-
reject(err);
|
|
55424
|
-
});
|
|
55425
|
-
}).on("error", reject);
|
|
55426
|
-
};
|
|
55427
|
-
doGet(url);
|
|
55428
|
-
});
|
|
55429
|
-
}
|
|
55430
55431
|
function getCurrentVersion() {
|
|
55431
55432
|
try {
|
|
55432
|
-
const pkg = path2.resolve(__dirname, "
|
|
55433
|
+
const pkg = path2.resolve(__dirname, "../package.json");
|
|
55433
55434
|
return JSON.parse(fs4.readFileSync(pkg, "utf-8")).version ?? "0.0.0";
|
|
55434
55435
|
} catch {
|
|
55435
55436
|
return "0.0.0";
|
|
@@ -55446,8 +55447,31 @@ function semverGt(a, b) {
|
|
|
55446
55447
|
}
|
|
55447
55448
|
return false;
|
|
55448
55449
|
}
|
|
55449
|
-
function
|
|
55450
|
-
|
|
55450
|
+
async function fetchLatestVersion() {
|
|
55451
|
+
const raw = await get2(NPM_REGISTRY_LATEST);
|
|
55452
|
+
const meta = JSON.parse(raw);
|
|
55453
|
+
return meta.version ?? "0.0.0";
|
|
55454
|
+
}
|
|
55455
|
+
function npmInstallGlobal() {
|
|
55456
|
+
return new Promise((resolve3) => {
|
|
55457
|
+
const { spawn } = __require("child_process");
|
|
55458
|
+
const child = spawn("npm", ["install", "-g", "nexrall-code"], { stdio: "pipe" });
|
|
55459
|
+
let stderr = "";
|
|
55460
|
+
child.stderr?.on("data", (c) => {
|
|
55461
|
+
stderr += c.toString();
|
|
55462
|
+
});
|
|
55463
|
+
child.on("close", (code) => {
|
|
55464
|
+
if (code === 0)
|
|
55465
|
+
return resolve3({ ok: true, usedSudo: false });
|
|
55466
|
+
if (/EACCES|permission denied/i.test(stderr)) {
|
|
55467
|
+
const sudo = spawn("sudo", ["npm", "install", "-g", "nexrall-code"], { stdio: "inherit" });
|
|
55468
|
+
sudo.on("close", (sudoCode) => resolve3({ ok: sudoCode === 0, usedSudo: true }));
|
|
55469
|
+
} else {
|
|
55470
|
+
console.error(source_default.dim(stderr.trim()));
|
|
55471
|
+
resolve3({ ok: false, usedSudo: false });
|
|
55472
|
+
}
|
|
55473
|
+
});
|
|
55474
|
+
});
|
|
55451
55475
|
}
|
|
55452
55476
|
async function updateCommand(opts) {
|
|
55453
55477
|
const current = getCurrentVersion();
|
|
@@ -55457,17 +55481,15 @@ async function updateCommand(opts) {
|
|
|
55457
55481
|
console.log(source_default.dim(` Current version: v${current}`));
|
|
55458
55482
|
console.log();
|
|
55459
55483
|
process.stdout.write(source_default.dim(" \u2192 Checking latest version\u2026"));
|
|
55460
|
-
let
|
|
55484
|
+
let latest;
|
|
55461
55485
|
try {
|
|
55462
|
-
|
|
55486
|
+
latest = await fetchLatestVersion();
|
|
55463
55487
|
process.stdout.write("\r\x1B[K");
|
|
55464
55488
|
} catch (e2) {
|
|
55465
55489
|
process.stdout.write("\r\x1B[K");
|
|
55466
|
-
console.error(source_default.red(" \u2717 Could not reach
|
|
55490
|
+
console.error(source_default.red(" \u2717 Could not reach npm registry: ") + String(e2.message));
|
|
55467
55491
|
process.exit(1);
|
|
55468
55492
|
}
|
|
55469
|
-
const latest = meta.version ?? "0.0.0";
|
|
55470
|
-
const binaryUrl = `${CDN_BASE}/nex`;
|
|
55471
55493
|
if (!semverGt(latest, current)) {
|
|
55472
55494
|
console.log(source_default.green(` \u2713 Already up to date \u2014 v${current}`));
|
|
55473
55495
|
console.log();
|
|
@@ -55497,70 +55519,15 @@ async function updateCommand(opts) {
|
|
|
55497
55519
|
}
|
|
55498
55520
|
console.log();
|
|
55499
55521
|
}
|
|
55500
|
-
|
|
55501
|
-
|
|
55502
|
-
|
|
55503
|
-
|
|
55504
|
-
|
|
55505
|
-
|
|
55506
|
-
console.log(source_default.dim(` \u2713 Downloaded v${latest}`));
|
|
55507
|
-
} catch (e2) {
|
|
55508
|
-
process.stdout.write("\r\x1B[K");
|
|
55509
|
-
console.error(source_default.red(" \u2717 Download failed: ") + String(e2.message));
|
|
55510
|
-
try {
|
|
55511
|
-
fs4.unlinkSync(tmpFile);
|
|
55512
|
-
} catch {
|
|
55513
|
-
}
|
|
55522
|
+
process.stdout.write(source_default.dim(` \u2192 Running npm install -g nexrall-code\u2026`));
|
|
55523
|
+
const { ok, usedSudo } = await npmInstallGlobal();
|
|
55524
|
+
process.stdout.write("\r\x1B[K");
|
|
55525
|
+
if (!ok) {
|
|
55526
|
+
console.error(source_default.red(" \u2717 Update failed. Run manually:"));
|
|
55527
|
+
console.error(source_default.dim(" npm install -g nexrall-code"));
|
|
55514
55528
|
process.exit(1);
|
|
55515
55529
|
}
|
|
55516
|
-
|
|
55517
|
-
if (!binPath || !fs4.existsSync(binPath)) {
|
|
55518
|
-
const fallbacks = ["/usr/local/bin/nex", `${os3.homedir()}/.local/bin/nex`];
|
|
55519
|
-
const found = fallbacks.find((p) => fs4.existsSync(p));
|
|
55520
|
-
if (!found) {
|
|
55521
|
-
console.log(source_default.yellow(" \u26A0 Could not locate nex binary to replace."));
|
|
55522
|
-
console.log(source_default.dim(` Downloaded binary is at: ${tmpFile}`));
|
|
55523
|
-
console.log(source_default.dim(" Move it manually: sudo mv " + tmpFile + " /usr/local/bin/nex"));
|
|
55524
|
-
return;
|
|
55525
|
-
}
|
|
55526
|
-
try {
|
|
55527
|
-
fs4.copyFileSync(tmpFile, found);
|
|
55528
|
-
fs4.chmodSync(found, 493);
|
|
55529
|
-
console.log(source_default.green(` \u2713 Updated \u2192 ${found}`));
|
|
55530
|
-
} catch {
|
|
55531
|
-
console.log(source_default.yellow(` \u26A0 No write permission to ${found}. Trying sudo\u2026`));
|
|
55532
|
-
const { spawnSync } = await import("child_process");
|
|
55533
|
-
const r2 = spawnSync("sudo", ["cp", tmpFile, found], { stdio: "inherit" });
|
|
55534
|
-
if (r2.status !== 0) {
|
|
55535
|
-
console.error(source_default.red(" \u2717 Update failed. Run manually:"));
|
|
55536
|
-
console.error(source_default.dim(` sudo cp ${tmpFile} ${found} && sudo chmod +x ${found}`));
|
|
55537
|
-
process.exit(1);
|
|
55538
|
-
}
|
|
55539
|
-
spawnSync("sudo", ["chmod", "+x", found], { stdio: "inherit" });
|
|
55540
|
-
console.log(source_default.green(` \u2713 Updated \u2192 ${found}`));
|
|
55541
|
-
}
|
|
55542
|
-
} else {
|
|
55543
|
-
try {
|
|
55544
|
-
fs4.copyFileSync(tmpFile, binPath);
|
|
55545
|
-
fs4.chmodSync(binPath, 493);
|
|
55546
|
-
console.log(source_default.green(` \u2713 Updated \u2192 ${binPath}`));
|
|
55547
|
-
} catch {
|
|
55548
|
-
const { spawnSync } = await import("child_process");
|
|
55549
|
-
console.log(source_default.yellow(` \u26A0 No write permission. Trying sudo\u2026`));
|
|
55550
|
-
const r2 = spawnSync("sudo", ["cp", tmpFile, binPath], { stdio: "inherit" });
|
|
55551
|
-
if (r2.status !== 0) {
|
|
55552
|
-
console.error(source_default.red(" \u2717 Update failed. Run manually:"));
|
|
55553
|
-
console.error(source_default.dim(` sudo cp ${tmpFile} ${binPath} && sudo chmod +x ${binPath}`));
|
|
55554
|
-
process.exit(1);
|
|
55555
|
-
}
|
|
55556
|
-
spawnSync("sudo", ["chmod", "+x", binPath], { stdio: "inherit" });
|
|
55557
|
-
console.log(source_default.green(` \u2713 Updated \u2192 ${binPath}`));
|
|
55558
|
-
}
|
|
55559
|
-
}
|
|
55560
|
-
try {
|
|
55561
|
-
fs4.unlinkSync(tmpFile);
|
|
55562
|
-
} catch {
|
|
55563
|
-
}
|
|
55530
|
+
console.log(source_default.green(` \u2713 Updated \u2192 v${latest}${usedSudo ? " (via sudo)" : ""}`));
|
|
55564
55531
|
console.log();
|
|
55565
55532
|
console.log(source_default.bold(` Nexrall CLI v${latest} installed!`));
|
|
55566
55533
|
console.log(source_default.dim(" Restart your terminal or run: exec $SHELL"));
|
|
@@ -55957,7 +55924,7 @@ __export(base_exports, {
|
|
|
55957
55924
|
synchronizedOutput: () => synchronizedOutput
|
|
55958
55925
|
});
|
|
55959
55926
|
import process3 from "node:process";
|
|
55960
|
-
import
|
|
55927
|
+
import os3 from "node:os";
|
|
55961
55928
|
|
|
55962
55929
|
// ../../node_modules/.pnpm/environment@1.1.0/node_modules/environment/index.js
|
|
55963
55930
|
var isBrowser = globalThis.window?.document !== void 0;
|
|
@@ -56056,7 +56023,7 @@ var isOldWindows = () => {
|
|
|
56056
56023
|
if (isBrowser || !isWindows2) {
|
|
56057
56024
|
return false;
|
|
56058
56025
|
}
|
|
56059
|
-
const parts =
|
|
56026
|
+
const parts = os3.release().split(".");
|
|
56060
56027
|
const major = Number(parts[0]);
|
|
56061
56028
|
const build = Number(parts[2] ?? 0);
|
|
56062
56029
|
if (major < 10) {
|
|
@@ -64751,7 +64718,7 @@ var InkReadlineAdapter = class extends EventEmitter3 {
|
|
|
64751
64718
|
};
|
|
64752
64719
|
|
|
64753
64720
|
// src/commands/chat.ts
|
|
64754
|
-
var CLI_VERSION = "0.5.
|
|
64721
|
+
var CLI_VERSION = "0.5.63";
|
|
64755
64722
|
var MODEL_LABELS = {
|
|
64756
64723
|
"claude-sonnet-5": "Claude Sonnet 5",
|
|
64757
64724
|
"claude-opus-5": "Claude Opus 5",
|
|
@@ -64759,7 +64726,10 @@ var MODEL_LABELS = {
|
|
|
64759
64726
|
"claude-haiku-4-5-20251001": "Claude Haiku 4.5",
|
|
64760
64727
|
"gpt-5.4": "GPT-5.4",
|
|
64761
64728
|
"gpt-5.4-mini": "GPT-5.4 Mini",
|
|
64762
|
-
"gpt-4.1": "GPT-4.1"
|
|
64729
|
+
"gpt-4.1": "GPT-4.1",
|
|
64730
|
+
"deepseek-v4-pro": "DeepSeek V4 Pro",
|
|
64731
|
+
"deepseek-v4-flash": "DeepSeek V4 Flash",
|
|
64732
|
+
"qwen3.7-max": "Qwen3.7 Max"
|
|
64763
64733
|
};
|
|
64764
64734
|
var LEGACY_MODEL_ALIASES = {
|
|
64765
64735
|
turbo: "claude-sonnet-5",
|
|
@@ -64775,7 +64745,10 @@ var SELECTABLE_MODELS = [
|
|
|
64775
64745
|
"claude-fable-5",
|
|
64776
64746
|
"gpt-5.4",
|
|
64777
64747
|
"gpt-5.4-mini",
|
|
64778
|
-
"gpt-4.1"
|
|
64748
|
+
"gpt-4.1",
|
|
64749
|
+
"deepseek-v4-pro",
|
|
64750
|
+
"deepseek-v4-flash",
|
|
64751
|
+
"qwen3.7-max"
|
|
64779
64752
|
];
|
|
64780
64753
|
function normaliseModelId(model) {
|
|
64781
64754
|
const raw = (model ?? "").trim();
|
|
@@ -64813,7 +64786,7 @@ function printBalanceNotice(balance, zero) {
|
|
|
64813
64786
|
}
|
|
64814
64787
|
function currentUserLabel() {
|
|
64815
64788
|
try {
|
|
64816
|
-
const u =
|
|
64789
|
+
const u = os4.userInfo().username;
|
|
64817
64790
|
return u ? u.charAt(0).toUpperCase() + u.slice(1) : "there";
|
|
64818
64791
|
} catch {
|
|
64819
64792
|
return "there";
|
|
@@ -64822,7 +64795,7 @@ function currentUserLabel() {
|
|
|
64822
64795
|
function collectEnv(workDir) {
|
|
64823
64796
|
return {
|
|
64824
64797
|
cwd: workDir,
|
|
64825
|
-
platform: `${
|
|
64798
|
+
platform: `${os4.platform()} ${os4.release()}`,
|
|
64826
64799
|
shell: process.env.SHELL ?? process.env.ComSpec ?? "unknown",
|
|
64827
64800
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
64828
64801
|
gitBranch: tryExec("git branch --show-current", workDir),
|
|
@@ -64849,7 +64822,7 @@ function readNexrallMd(workDir) {
|
|
|
64849
64822
|
const memContent = (0, import_code_core3.readAllMemory)(workDir);
|
|
64850
64823
|
if (memContent)
|
|
64851
64824
|
parts.push(memContent);
|
|
64852
|
-
const globalContent = tryRead(path4.join(
|
|
64825
|
+
const globalContent = tryRead(path4.join(os4.homedir(), ".nexrall", "nexrall.md"));
|
|
64853
64826
|
if (globalContent)
|
|
64854
64827
|
parts.push(`[Global instructions]
|
|
64855
64828
|
${globalContent}`);
|
|
@@ -66454,7 +66427,7 @@ function pluginSourceRemoveCommand(name, opts) {
|
|
|
66454
66427
|
|
|
66455
66428
|
// src/index.ts
|
|
66456
66429
|
var program2 = new Command();
|
|
66457
|
-
program2.name("nex").description("Nexrall Code \u2014 AI coding assistant (powered by Nexrall)").version("0.5.
|
|
66430
|
+
program2.name("nex").description("Nexrall Code \u2014 AI coding assistant (powered by Nexrall)").version("0.5.63").enablePositionalOptions();
|
|
66458
66431
|
program2.command("auth").description("Login to your Nexrall account").action(authCommand);
|
|
66459
66432
|
program2.command("logout").description("Log out of your Nexrall account").action(logoutCommand);
|
|
66460
66433
|
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/install.ps1
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
# Nexrall Code CLI — Windows Installer
|
|
2
|
-
# Usage: irm https://nexrall.com/install.ps1 | iex
|
|
2
|
+
# Usage: irm https://cli.nexrall.com/install.ps1 | iex
|
|
3
3
|
#
|
|
4
4
|
# What it does:
|
|
5
|
-
# 1. Check Node.js >= 18
|
|
6
|
-
# 2.
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
5
|
+
# 1. Check Node.js >= 18 (npm ships with it)
|
|
6
|
+
# 2. Install the `nex` package globally from the npm registry
|
|
7
|
+
#
|
|
8
|
+
# Why npm and not a hand-rolled CDN/binary download: npm's registry is
|
|
9
|
+
# already the correct source of truth for "what is the latest version" —
|
|
10
|
+
# `npm install -g nexrall-code` always resolves to the current `latest`
|
|
11
|
+
# dist-tag with zero extra infrastructure to keep in sync. A previous
|
|
12
|
+
# version of this script downloaded a binary from a custom CDN path whose
|
|
13
|
+
# "latest version" metadata was a hardcoded backend fallback that had
|
|
14
|
+
# drifted 5 months out of date — every install silently got a broken build.
|
|
10
15
|
|
|
11
16
|
$ErrorActionPreference = 'Stop'
|
|
12
17
|
|
|
13
|
-
$API_LATEST = 'https://api.nexrall.com/api/code/cli/latest'
|
|
14
|
-
$INSTALL_DIR = "$env:LOCALAPPDATA\nexrall-cli"
|
|
15
|
-
$BINARY_JS = "$INSTALL_DIR\nex.js"
|
|
16
|
-
$WRAPPER_CMD = "$INSTALL_DIR\nex.cmd"
|
|
17
|
-
|
|
18
18
|
Write-Host ""
|
|
19
19
|
Write-Host " Nexrall Code CLI — Installer" -ForegroundColor Cyan -NoNewline
|
|
20
20
|
Write-Host ""
|
|
@@ -37,63 +37,29 @@ try {
|
|
|
37
37
|
exit 1
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
# ── Fetch latest version ───────────────────────────────────────────────────────
|
|
41
|
-
Write-Host " → Checking latest version…" -ForegroundColor DarkGray
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
$meta = Invoke-RestMethod -Uri $API_LATEST -UseBasicParsing
|
|
45
|
-
$version = $meta.version
|
|
46
|
-
$binaryUrl = $meta.url
|
|
47
|
-
} catch {
|
|
48
|
-
# Fallback
|
|
49
|
-
$version = "latest"
|
|
50
|
-
$binaryUrl = "https://media.nexrall.com/cli/nex"
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
Write-Host " → Version: $version" -ForegroundColor DarkGray
|
|
54
|
-
Write-Host " → Download: $binaryUrl" -ForegroundColor DarkGray
|
|
55
|
-
|
|
56
|
-
# ── Download binary ───────────────────────────────────────────────────────────
|
|
57
|
-
Write-Host " → Downloading…" -ForegroundColor DarkGray
|
|
58
|
-
|
|
59
|
-
New-Item -ItemType Directory -Force -Path $INSTALL_DIR | Out-Null
|
|
60
|
-
$TMP = "$env:TEMP\nex_tmp.js"
|
|
61
|
-
|
|
62
40
|
try {
|
|
63
|
-
|
|
41
|
+
npm --version 2>$null | Out-Null
|
|
64
42
|
} catch {
|
|
65
|
-
Write-Host " ✗
|
|
43
|
+
Write-Host " ✗ npm not found (it normally ships with Node.js). Please reinstall Node.js from https://nodejs.org" -ForegroundColor Red
|
|
66
44
|
exit 1
|
|
67
45
|
}
|
|
68
46
|
|
|
69
|
-
#
|
|
70
|
-
|
|
47
|
+
# ── Install via npm ────────────────────────────────────────────────────────────
|
|
48
|
+
Write-Host " → Installing nexrall-code (latest) from npm…" -ForegroundColor DarkGray
|
|
49
|
+
|
|
50
|
+
npm install -g nexrall-code
|
|
71
51
|
if ($LASTEXITCODE -ne 0) {
|
|
72
|
-
|
|
73
|
-
Write-Host " ✗ Downloaded binary failed sanity check." -ForegroundColor Red
|
|
52
|
+
Write-Host " ✗ npm install failed." -ForegroundColor Red
|
|
74
53
|
exit 1
|
|
75
54
|
}
|
|
55
|
+
Write-Host " ✓ Installed" -ForegroundColor Green
|
|
76
56
|
|
|
77
|
-
# ──
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
Write-Host " ✓ Installed to $INSTALL_DIR" -ForegroundColor Green
|
|
85
|
-
|
|
86
|
-
# ── Add to PATH ───────────────────────────────────────────────────────────────
|
|
87
|
-
$userPath = [System.Environment]::GetEnvironmentVariable('PATH', 'User')
|
|
88
|
-
if ($userPath -notlike "*$INSTALL_DIR*") {
|
|
89
|
-
[System.Environment]::SetEnvironmentVariable(
|
|
90
|
-
'PATH',
|
|
91
|
-
"$INSTALL_DIR;$userPath",
|
|
92
|
-
'User'
|
|
93
|
-
)
|
|
94
|
-
Write-Host " ✓ Added to PATH (restart your terminal to apply)" -ForegroundColor Green
|
|
95
|
-
} else {
|
|
96
|
-
Write-Host " ✓ Already in PATH" -ForegroundColor Green
|
|
57
|
+
# ── Sanity check ───────────────────────────────────────────────────────────────
|
|
58
|
+
try {
|
|
59
|
+
$installedVersion = (nex --version 2>$null)
|
|
60
|
+
Write-Host " ✓ $installedVersion" -ForegroundColor Green
|
|
61
|
+
} catch {
|
|
62
|
+
Write-Host " ⚠ 'nex' installed but not found on PATH yet. Open a new terminal window." -ForegroundColor Yellow
|
|
97
63
|
}
|
|
98
64
|
|
|
99
65
|
# ── Done ──────────────────────────────────────────────────────────────────────
|
package/install.sh
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env sh
|
|
2
2
|
# Nexrall Code CLI — installer
|
|
3
|
-
# Usage: curl -fsSL https://nexrall.com/install.sh | sh
|
|
3
|
+
# Usage: curl -fsSL https://cli.nexrall.com/install.sh | sh
|
|
4
4
|
#
|
|
5
5
|
# What it does:
|
|
6
|
-
# 1.
|
|
7
|
-
# 2.
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
6
|
+
# 1. Check Node.js >= 18 (npm ships with it — no separate check needed)
|
|
7
|
+
# 2. Install the `nex` package globally from the npm registry
|
|
8
|
+
#
|
|
9
|
+
# Why npm and not a hand-rolled CDN/binary download: npm's registry is
|
|
10
|
+
# already the correct source of truth for "what is the latest version" —
|
|
11
|
+
# `npm install -g nexrall-code` always resolves to the current `latest`
|
|
12
|
+
# dist-tag with zero extra infrastructure to keep in sync. A previous
|
|
13
|
+
# version of this script downloaded a binary from a custom CDN path whose
|
|
14
|
+
# "latest version" metadata was a hardcoded fallback in the backend that had
|
|
15
|
+
# drifted 5 months out of date — every install silently got a broken build.
|
|
16
|
+
# Delegating to npm removes that entire class of bug.
|
|
11
17
|
|
|
12
18
|
set -e
|
|
13
19
|
|
|
14
|
-
BINARY_NAME="nex"
|
|
15
|
-
CDN_BASE="https://cli.nexrall.com"
|
|
16
|
-
API_LATEST="https://api.nexrall.com/api/code/cli/latest"
|
|
17
|
-
INSTALL_DIR="/usr/local/bin"
|
|
18
|
-
|
|
19
|
-
# ── Colors ────────────────────────────────────────────────────────────────────
|
|
20
20
|
bold=""
|
|
21
21
|
dim=""
|
|
22
22
|
green=""
|
|
@@ -37,29 +37,10 @@ success() { printf "${green} ✓${reset} %s\n" "$*"; }
|
|
|
37
37
|
error() { printf "${red} ✗${reset} %s\n" "$*" >&2; }
|
|
38
38
|
fatal() { error "$*"; exit 1; }
|
|
39
39
|
|
|
40
|
-
# ── Banner ────────────────────────────────────────────────────────────────────
|
|
41
40
|
printf "\n"
|
|
42
41
|
printf "${bold} Nexrall Code CLI — Installer${reset}\n"
|
|
43
42
|
printf "${dim} ────────────────────────────────────${reset}\n\n"
|
|
44
43
|
|
|
45
|
-
# ── OS detection ──────────────────────────────────────────────────────────────
|
|
46
|
-
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
|
|
47
|
-
ARCH=$(uname -m)
|
|
48
|
-
|
|
49
|
-
case "$OS" in
|
|
50
|
-
darwin) PLATFORM="macos" ;;
|
|
51
|
-
linux) PLATFORM="linux" ;;
|
|
52
|
-
*) fatal "Unsupported OS: $OS. Please install manually." ;;
|
|
53
|
-
esac
|
|
54
|
-
|
|
55
|
-
case "$ARCH" in
|
|
56
|
-
x86_64|amd64) ARCH_TAG="x64" ;;
|
|
57
|
-
arm64|aarch64) ARCH_TAG="arm64" ;;
|
|
58
|
-
*) ARCH_TAG="x64" ;; # fallback
|
|
59
|
-
esac
|
|
60
|
-
|
|
61
|
-
info "Detected: ${PLATFORM} / ${ARCH_TAG}"
|
|
62
|
-
|
|
63
44
|
# ── Node.js check ─────────────────────────────────────────────────────────────
|
|
64
45
|
if ! command -v node >/dev/null 2>&1; then
|
|
65
46
|
printf "\n"
|
|
@@ -78,82 +59,37 @@ fi
|
|
|
78
59
|
|
|
79
60
|
success "Node.js $(node --version)"
|
|
80
61
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if command -v curl >/dev/null 2>&1; then
|
|
85
|
-
LATEST_JSON=$(curl -fsSL "$API_LATEST" 2>/dev/null || echo '{}')
|
|
86
|
-
elif command -v wget >/dev/null 2>&1; then
|
|
87
|
-
LATEST_JSON=$(wget -qO- "$API_LATEST" 2>/dev/null || echo '{}')
|
|
88
|
-
else
|
|
89
|
-
fatal "curl or wget is required to download the installer."
|
|
90
|
-
fi
|
|
91
|
-
|
|
92
|
-
# Parse version from JSON (simple sed, no jq dependency)
|
|
93
|
-
VERSION=$(echo "$LATEST_JSON" | sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
|
|
94
|
-
BINARY_URL=$(echo "$LATEST_JSON" | sed -n 's/.*"url"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
|
|
95
|
-
|
|
96
|
-
if [ -z "$VERSION" ] || [ -z "$BINARY_URL" ]; then
|
|
97
|
-
# Fallback: construct URL directly (single universal Node.js binary)
|
|
98
|
-
VERSION="latest"
|
|
99
|
-
BINARY_URL="${CDN_BASE}/nex"
|
|
100
|
-
fi
|
|
101
|
-
|
|
102
|
-
info "Version: ${VERSION}"
|
|
103
|
-
info "Download: ${BINARY_URL}"
|
|
104
|
-
|
|
105
|
-
# ── Download binary ───────────────────────────────────────────────────────────
|
|
106
|
-
TMP_FILE=$(mktemp /tmp/nex_XXXXXX)
|
|
107
|
-
|
|
108
|
-
info "Downloading…"
|
|
109
|
-
if command -v curl >/dev/null 2>&1; then
|
|
110
|
-
curl -fsSL --progress-bar "$BINARY_URL" -o "$TMP_FILE"
|
|
111
|
-
elif command -v wget >/dev/null 2>&1; then
|
|
112
|
-
wget -q --show-progress "$BINARY_URL" -O "$TMP_FILE"
|
|
113
|
-
fi
|
|
114
|
-
|
|
115
|
-
chmod +x "$TMP_FILE"
|
|
116
|
-
|
|
117
|
-
# Quick sanity check
|
|
118
|
-
if ! node "$TMP_FILE" --version >/dev/null 2>&1; then
|
|
119
|
-
rm -f "$TMP_FILE"
|
|
120
|
-
fatal "Downloaded binary failed sanity check. Please try again."
|
|
62
|
+
if ! command -v npm >/dev/null 2>&1; then
|
|
63
|
+
fatal "npm not found (it normally ships with Node.js). Please reinstall Node.js from https://nodejs.org."
|
|
121
64
|
fi
|
|
122
65
|
|
|
123
|
-
# ── Install
|
|
124
|
-
|
|
66
|
+
# ── Install via npm ────────────────────────────────────────────────────────────
|
|
67
|
+
info "Installing nexrall-code (latest) from npm…"
|
|
125
68
|
|
|
126
|
-
if
|
|
127
|
-
|
|
128
|
-
success "Installed to ${TARGET}"
|
|
69
|
+
if npm install -g nexrall-code; then
|
|
70
|
+
success "Installed"
|
|
129
71
|
else
|
|
130
|
-
#
|
|
72
|
+
# Global install can fail on permissions (e.g. system Node without a user
|
|
73
|
+
# prefix configured). Retry with sudo before giving up.
|
|
131
74
|
if command -v sudo >/dev/null 2>&1; then
|
|
132
|
-
info "
|
|
133
|
-
sudo
|
|
134
|
-
|
|
135
|
-
success "Installed to ${TARGET} (via sudo)"
|
|
75
|
+
info "Retrying with sudo…"
|
|
76
|
+
sudo npm install -g nexrall-code || fatal "npm install failed. Try: npm config set prefix ~/.npm-global"
|
|
77
|
+
success "Installed (via sudo)"
|
|
136
78
|
else
|
|
137
|
-
|
|
138
|
-
FALLBACK_DIR="$HOME/.local/bin"
|
|
139
|
-
mkdir -p "$FALLBACK_DIR"
|
|
140
|
-
mv "$TMP_FILE" "${FALLBACK_DIR}/${BINARY_NAME}"
|
|
141
|
-
chmod +x "${FALLBACK_DIR}/${BINARY_NAME}"
|
|
142
|
-
TARGET="${FALLBACK_DIR}/${BINARY_NAME}"
|
|
143
|
-
success "Installed to ${TARGET}"
|
|
144
|
-
|
|
145
|
-
# Check if fallback dir is on PATH
|
|
146
|
-
case ":$PATH:" in
|
|
147
|
-
*":${FALLBACK_DIR}:"*) ;;
|
|
148
|
-
*)
|
|
149
|
-
printf "\n"
|
|
150
|
-
printf " ${dim}Add this to your shell profile (~/.zshrc or ~/.bashrc):${reset}\n"
|
|
151
|
-
printf " ${cyan}export PATH=\"\$HOME/.local/bin:\$PATH\"${reset}\n"
|
|
152
|
-
;;
|
|
153
|
-
esac
|
|
79
|
+
fatal "npm install failed. Try: npm config set prefix ~/.npm-global && npm install -g nexrall-code"
|
|
154
80
|
fi
|
|
155
81
|
fi
|
|
156
82
|
|
|
83
|
+
if ! command -v nex >/dev/null 2>&1; then
|
|
84
|
+
printf "\n"
|
|
85
|
+
error "'nex' installed but is not on PATH."
|
|
86
|
+
printf " Find npm's global bin dir with: ${cyan}npm bin -g${reset}\n"
|
|
87
|
+
printf " Then add it to PATH in your shell profile.\n\n"
|
|
88
|
+
exit 1
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
success "$(nex --version 2>/dev/null | head -1)"
|
|
92
|
+
|
|
157
93
|
# ── Done ──────────────────────────────────────────────────────────────────────
|
|
158
94
|
printf "\n"
|
|
159
95
|
printf "${bold}${green} Nexrall Code CLI installed successfully!${reset}\n\n"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexrall-code",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.63",
|
|
4
4
|
"description": "Nexrall Code — AI coding assistant for your terminal (headless agent for scripts, CI and automation)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"release": "node build.js && node scripts/upload-release.cjs"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@nexrall/code-core": "^1.4.
|
|
42
|
+
"@nexrall/code-core": "^1.4.37",
|
|
43
43
|
"chalk": "^5.3.0",
|
|
44
44
|
"commander": "^12.0.0",
|
|
45
45
|
"diff": "^5.2.0",
|