buildwithnexus 0.4.0 → 0.4.2
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/bin.js +37 -97
- package/dist/nexus-release.tar.gz +0 -0
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -341,9 +341,9 @@ var init_secrets = __esm({
|
|
|
341
341
|
"src/core/secrets.ts"() {
|
|
342
342
|
"use strict";
|
|
343
343
|
init_dlp();
|
|
344
|
-
NEXUS_HOME2 =
|
|
345
|
-
CONFIG_PATH =
|
|
346
|
-
KEYS_PATH =
|
|
344
|
+
NEXUS_HOME2 = path2.join(process.env.HOME || "~", ".buildwithnexus");
|
|
345
|
+
CONFIG_PATH = path2.join(NEXUS_HOME2, "config.json");
|
|
346
|
+
KEYS_PATH = path2.join(NEXUS_HOME2, ".env.keys");
|
|
347
347
|
}
|
|
348
348
|
});
|
|
349
349
|
|
|
@@ -673,11 +673,9 @@ function addSshConfig(port) {
|
|
|
673
673
|
}
|
|
674
674
|
async function waitForSsh(port, timeoutMs = 3e5) {
|
|
675
675
|
const start = Date.now();
|
|
676
|
-
let attempt = 0;
|
|
677
|
-
const backoffMs = (n) => Math.min(3e3 * Math.pow(2, n), 3e4);
|
|
678
676
|
while (Date.now() - start < timeoutMs) {
|
|
679
|
-
const ssh = new NodeSSH();
|
|
680
677
|
try {
|
|
678
|
+
const ssh = new NodeSSH();
|
|
681
679
|
await ssh.connect({
|
|
682
680
|
host: "localhost",
|
|
683
681
|
port,
|
|
@@ -689,14 +687,7 @@ async function waitForSsh(port, timeoutMs = 3e5) {
|
|
|
689
687
|
ssh.dispose();
|
|
690
688
|
return true;
|
|
691
689
|
} catch {
|
|
692
|
-
|
|
693
|
-
ssh.dispose();
|
|
694
|
-
} catch {
|
|
695
|
-
}
|
|
696
|
-
const delay = backoffMs(attempt++);
|
|
697
|
-
const remaining = timeoutMs - (Date.now() - start);
|
|
698
|
-
if (remaining <= 0) break;
|
|
699
|
-
await new Promise((r) => setTimeout(r, Math.min(delay, remaining)));
|
|
690
|
+
await new Promise((r) => setTimeout(r, 5e3));
|
|
700
691
|
}
|
|
701
692
|
}
|
|
702
693
|
return false;
|
|
@@ -785,13 +776,6 @@ var log = {
|
|
|
785
776
|
},
|
|
786
777
|
detail(label, value) {
|
|
787
778
|
console.log(chalk3.dim(" " + label + ": ") + value);
|
|
788
|
-
},
|
|
789
|
-
progress(current, total, label) {
|
|
790
|
-
const pct = Math.round(current / total * 100);
|
|
791
|
-
const filled = Math.round(current / total * 20);
|
|
792
|
-
const bar = chalk3.cyan("\u2588".repeat(filled)) + chalk3.dim("\u2591".repeat(20 - filled));
|
|
793
|
-
process.stdout.write(`\r [${bar}] ${chalk3.bold(`${pct}%`)} ${chalk3.dim(label)}`);
|
|
794
|
-
if (current >= total) process.stdout.write("\n");
|
|
795
779
|
}
|
|
796
780
|
};
|
|
797
781
|
|
|
@@ -1033,12 +1017,7 @@ async function checkHealth(port, vmRunning) {
|
|
|
1033
1017
|
sshReady: false,
|
|
1034
1018
|
dockerReady: false,
|
|
1035
1019
|
serverHealthy: false,
|
|
1036
|
-
tunnelUrl: null
|
|
1037
|
-
dockerVersion: null,
|
|
1038
|
-
serverVersion: null,
|
|
1039
|
-
diskUsagePercent: null,
|
|
1040
|
-
uptimeSeconds: null,
|
|
1041
|
-
lastChecked: (/* @__PURE__ */ new Date()).toISOString()
|
|
1020
|
+
tunnelUrl: null
|
|
1042
1021
|
};
|
|
1043
1022
|
if (!vmRunning) return status;
|
|
1044
1023
|
try {
|
|
@@ -1048,33 +1027,13 @@ async function checkHealth(port, vmRunning) {
|
|
|
1048
1027
|
return status;
|
|
1049
1028
|
}
|
|
1050
1029
|
try {
|
|
1051
|
-
const {
|
|
1052
|
-
status.dockerReady = code === 0
|
|
1053
|
-
if (status.dockerReady) status.dockerVersion = stdout.trim();
|
|
1030
|
+
const { code } = await sshExec(port, "docker version --format '{{.Server.Version}}'");
|
|
1031
|
+
status.dockerReady = code === 0;
|
|
1054
1032
|
} catch {
|
|
1055
1033
|
}
|
|
1056
1034
|
try {
|
|
1057
1035
|
const { stdout, code } = await sshExec(port, "curl -sf http://localhost:4200/health");
|
|
1058
1036
|
status.serverHealthy = code === 0 && stdout.includes("ok");
|
|
1059
|
-
if (status.serverHealthy) {
|
|
1060
|
-
try {
|
|
1061
|
-
const parsed = JSON.parse(stdout);
|
|
1062
|
-
if (typeof parsed.version === "string") status.serverVersion = parsed.version;
|
|
1063
|
-
} catch {
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
} catch {
|
|
1067
|
-
}
|
|
1068
|
-
try {
|
|
1069
|
-
const { stdout } = await sshExec(port, "df / --output=pcent | tail -1 | tr -dc '0-9'");
|
|
1070
|
-
const pct = parseInt(stdout.trim(), 10);
|
|
1071
|
-
if (!isNaN(pct)) status.diskUsagePercent = pct;
|
|
1072
|
-
} catch {
|
|
1073
|
-
}
|
|
1074
|
-
try {
|
|
1075
|
-
const { stdout } = await sshExec(port, "awk '{print int($1)}' /proc/uptime 2>/dev/null");
|
|
1076
|
-
const up = parseInt(stdout.trim(), 10);
|
|
1077
|
-
if (!isNaN(up)) status.uptimeSeconds = up;
|
|
1078
1037
|
} catch {
|
|
1079
1038
|
}
|
|
1080
1039
|
try {
|
|
@@ -1089,8 +1048,6 @@ async function checkHealth(port, vmRunning) {
|
|
|
1089
1048
|
async function waitForServer(port, timeoutMs = 9e5) {
|
|
1090
1049
|
const start = Date.now();
|
|
1091
1050
|
let lastLog = 0;
|
|
1092
|
-
let attempt = 0;
|
|
1093
|
-
const backoffMs = (n) => Math.min(3e3 * Math.pow(2, n), 3e4);
|
|
1094
1051
|
while (Date.now() - start < timeoutMs) {
|
|
1095
1052
|
try {
|
|
1096
1053
|
const { stdout, code } = await sshExec(port, "curl -sf http://localhost:4200/health");
|
|
@@ -1108,18 +1065,13 @@ async function waitForServer(port, timeoutMs = 9e5) {
|
|
|
1108
1065
|
} catch {
|
|
1109
1066
|
}
|
|
1110
1067
|
}
|
|
1111
|
-
|
|
1112
|
-
const remaining = timeoutMs - (Date.now() - start);
|
|
1113
|
-
if (remaining <= 0) break;
|
|
1114
|
-
await new Promise((r) => setTimeout(r, Math.min(delay, remaining)));
|
|
1068
|
+
await new Promise((r) => setTimeout(r, 5e3));
|
|
1115
1069
|
}
|
|
1116
1070
|
return false;
|
|
1117
1071
|
}
|
|
1118
1072
|
async function waitForCloudInit(port, timeoutMs = 18e5) {
|
|
1119
1073
|
const start = Date.now();
|
|
1120
1074
|
let lastLog = 0;
|
|
1121
|
-
let attempt = 0;
|
|
1122
|
-
const backoffMs = (n) => Math.min(3e3 * Math.pow(2, n), 3e4);
|
|
1123
1075
|
while (Date.now() - start < timeoutMs) {
|
|
1124
1076
|
try {
|
|
1125
1077
|
const { code } = await sshExec(port, "test -f /var/lib/cloud/instance/boot-finished");
|
|
@@ -1137,10 +1089,7 @@ async function waitForCloudInit(port, timeoutMs = 18e5) {
|
|
|
1137
1089
|
} catch {
|
|
1138
1090
|
}
|
|
1139
1091
|
}
|
|
1140
|
-
|
|
1141
|
-
const remaining = timeoutMs - (Date.now() - start);
|
|
1142
|
-
if (remaining <= 0) break;
|
|
1143
|
-
await new Promise((r) => setTimeout(r, Math.min(delay, remaining)));
|
|
1092
|
+
await new Promise((r) => setTimeout(r, 2e4));
|
|
1144
1093
|
}
|
|
1145
1094
|
return false;
|
|
1146
1095
|
}
|
|
@@ -1206,11 +1155,18 @@ import crypto4 from "crypto";
|
|
|
1206
1155
|
import { fileURLToPath } from "url";
|
|
1207
1156
|
function getReleaseTarball() {
|
|
1208
1157
|
const dir = path6.dirname(fileURLToPath(import.meta.url));
|
|
1209
|
-
const
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1158
|
+
const possiblePaths = [
|
|
1159
|
+
// Current directory (dev)
|
|
1160
|
+
path6.join(dir, "nexus-release.tar.gz"),
|
|
1161
|
+
// dist folder (when built)
|
|
1162
|
+
path6.resolve(dir, "..", "dist", "nexus-release.tar.gz"),
|
|
1163
|
+
// node_modules location (when installed from npm)
|
|
1164
|
+
path6.resolve(dir, "..", "nexus-release.tar.gz")
|
|
1165
|
+
];
|
|
1166
|
+
for (const tarballPath of possiblePaths) {
|
|
1167
|
+
if (fs6.existsSync(tarballPath)) return tarballPath;
|
|
1168
|
+
}
|
|
1169
|
+
throw new Error("nexus-release.tar.gz not found. Run: npm install buildwithnexus@latest");
|
|
1214
1170
|
}
|
|
1215
1171
|
function getCloudInitTemplate() {
|
|
1216
1172
|
const dir = path6.dirname(fileURLToPath(import.meta.url));
|
|
@@ -1613,13 +1569,9 @@ var statusCommand = new Command4("status").description("Check NEXUS runtime heal
|
|
|
1613
1569
|
console.log("");
|
|
1614
1570
|
console.log(` ${check(health.vmRunning)} VM ${health.vmRunning ? chalk7.green("running") + chalk7.dim(` (PID ${getVmPid()})`) : chalk7.red("stopped")}`);
|
|
1615
1571
|
console.log(` ${check(health.sshReady)} SSH ${health.sshReady ? chalk7.green("connected") + chalk7.dim(` (port ${config.sshPort})`) : chalk7.red("unreachable")}`);
|
|
1616
|
-
console.log(` ${check(health.dockerReady)} Docker ${health.dockerReady ? chalk7.green("ready")
|
|
1617
|
-
console.log(` ${check(health.serverHealthy)} Server ${health.serverHealthy ? chalk7.green("healthy") + chalk7.dim(` (port ${config.httpPort})`)
|
|
1572
|
+
console.log(` ${check(health.dockerReady)} Docker ${health.dockerReady ? chalk7.green("ready") : chalk7.red("not ready")}`);
|
|
1573
|
+
console.log(` ${check(health.serverHealthy)} Server ${health.serverHealthy ? chalk7.green("healthy") + chalk7.dim(` (port ${config.httpPort})`) : chalk7.red("unhealthy")}`);
|
|
1618
1574
|
console.log(` ${check(!!health.tunnelUrl)} Tunnel ${health.tunnelUrl ? chalk7.green(health.tunnelUrl) : chalk7.dim("not active")}`);
|
|
1619
|
-
if (health.diskUsagePercent !== null) {
|
|
1620
|
-
const diskOk = health.diskUsagePercent < 85;
|
|
1621
|
-
console.log(` ${check(diskOk)} Disk ${diskOk ? chalk7.green(`${health.diskUsagePercent}% used`) : chalk7.yellow(`${health.diskUsagePercent}% used \u2014 consider cleanup`)}`);
|
|
1622
|
-
}
|
|
1623
1575
|
console.log("");
|
|
1624
1576
|
if (health.serverHealthy) {
|
|
1625
1577
|
log.success(`NEXUS CLI ready \u2014 connect via: buildwithnexus ssh`);
|
|
@@ -1746,11 +1698,18 @@ init_qemu();
|
|
|
1746
1698
|
init_ssh();
|
|
1747
1699
|
function getReleaseTarball2() {
|
|
1748
1700
|
const dir = path9.dirname(fileURLToPath2(import.meta.url));
|
|
1749
|
-
const
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1701
|
+
const possiblePaths = [
|
|
1702
|
+
// Current directory (dev)
|
|
1703
|
+
path9.join(dir, "nexus-release.tar.gz"),
|
|
1704
|
+
// dist folder (when built)
|
|
1705
|
+
path9.resolve(dir, "..", "dist", "nexus-release.tar.gz"),
|
|
1706
|
+
// node_modules location (when installed from npm)
|
|
1707
|
+
path9.resolve(dir, "..", "nexus-release.tar.gz")
|
|
1708
|
+
];
|
|
1709
|
+
for (const tarballPath of possiblePaths) {
|
|
1710
|
+
if (fs8.existsSync(tarballPath)) return tarballPath;
|
|
1711
|
+
}
|
|
1712
|
+
throw new Error("nexus-release.tar.gz not found. Run: npm install buildwithnexus@latest");
|
|
1754
1713
|
}
|
|
1755
1714
|
var updateCommand = new Command7("update").description("Update NEXUS to the latest bundled release and restart").action(async () => {
|
|
1756
1715
|
const config = loadConfig();
|
|
@@ -2451,18 +2410,9 @@ var EventStream = class {
|
|
|
2451
2410
|
lastId = "0";
|
|
2452
2411
|
onEvent;
|
|
2453
2412
|
pollInterval = null;
|
|
2454
|
-
consecutiveErrors = 0;
|
|
2455
|
-
lastError = null;
|
|
2456
2413
|
constructor(onEvent) {
|
|
2457
2414
|
this.onEvent = onEvent;
|
|
2458
2415
|
}
|
|
2459
|
-
getStatus() {
|
|
2460
|
-
return {
|
|
2461
|
-
active: this.active,
|
|
2462
|
-
consecutiveErrors: this.consecutiveErrors,
|
|
2463
|
-
lastError: this.lastError
|
|
2464
|
-
};
|
|
2465
|
-
}
|
|
2466
2416
|
async start() {
|
|
2467
2417
|
this.active = true;
|
|
2468
2418
|
const config = loadConfig();
|
|
@@ -2475,23 +2425,13 @@ var EventStream = class {
|
|
|
2475
2425
|
`curl -sf -H 'Last-Event-ID: ${this.lastId}' http://localhost:4200/events?timeout=1 2>/dev/null || true`
|
|
2476
2426
|
);
|
|
2477
2427
|
if (code === 0 && stdout.trim()) {
|
|
2478
|
-
this.consecutiveErrors = 0;
|
|
2479
|
-
this.lastError = null;
|
|
2480
2428
|
const events = parseSSEData(stdout);
|
|
2481
2429
|
for (const event of events) {
|
|
2482
2430
|
if (event.id) this.lastId = event.id;
|
|
2483
2431
|
this.onEvent(event);
|
|
2484
2432
|
}
|
|
2485
2433
|
}
|
|
2486
|
-
} catch
|
|
2487
|
-
this.consecutiveErrors++;
|
|
2488
|
-
this.lastError = err instanceof Error ? err.message : String(err);
|
|
2489
|
-
if (this.consecutiveErrors >= 5) {
|
|
2490
|
-
this.onEvent({
|
|
2491
|
-
type: "error",
|
|
2492
|
-
content: `Event stream disconnected after ${this.consecutiveErrors} attempts: ${this.lastError}`
|
|
2493
|
-
});
|
|
2494
|
-
}
|
|
2434
|
+
} catch {
|
|
2495
2435
|
}
|
|
2496
2436
|
}, 2e3);
|
|
2497
2437
|
}
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "buildwithnexus",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "Launch an autonomous AI runtime with triple-nested VM isolation in one command",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"test": "vitest run",
|
|
20
20
|
"test:watch": "vitest",
|
|
21
21
|
"test:coverage": "vitest run --coverage",
|
|
22
|
-
"prepublishOnly": "npm run build"
|
|
22
|
+
"prepublishOnly": "npm run build && NEXUS_SRC=/Users/garretteaglin/Projects/nexus npm run bundle"
|
|
23
23
|
},
|
|
24
24
|
"engines": {
|
|
25
25
|
"node": ">=18"
|