buildwithnexus 0.2.4 → 0.2.6
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 +128 -58
- package/dist/nexus-release.tar.gz +0 -0
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -16,7 +16,7 @@ var BANNER = `
|
|
|
16
16
|
`;
|
|
17
17
|
function showBanner() {
|
|
18
18
|
console.log(BANNER);
|
|
19
|
-
console.log(chalk.dim(" v0.2.
|
|
19
|
+
console.log(chalk.dim(" v0.2.6 \xB7 buildwithnexus.dev\n"));
|
|
20
20
|
}
|
|
21
21
|
function showPhase(phase, total, description) {
|
|
22
22
|
const progress = chalk.cyan(`[${phase}/${total}]`);
|
|
@@ -461,6 +461,8 @@ import fs3 from "fs";
|
|
|
461
461
|
import net from "net";
|
|
462
462
|
import path3 from "path";
|
|
463
463
|
import { execa } from "execa";
|
|
464
|
+
import { select } from "@inquirer/prompts";
|
|
465
|
+
import chalk5 from "chalk";
|
|
464
466
|
var VM_DIR = path3.join(NEXUS_HOME2, "vm");
|
|
465
467
|
var IMAGES_DIR = path3.join(VM_DIR, "images");
|
|
466
468
|
var PID_FILE = path3.join(VM_DIR, "qemu.pid");
|
|
@@ -500,29 +502,95 @@ async function createDisk(basePath, sizeGb) {
|
|
|
500
502
|
await execa("qemu-img", ["create", "-f", "qcow2", "-b", basePath, "-F", "qcow2", diskPath, `${sizeGb}G`], { env: scrubEnv() });
|
|
501
503
|
return diskPath;
|
|
502
504
|
}
|
|
503
|
-
function
|
|
505
|
+
function tryBind(port, host) {
|
|
504
506
|
return new Promise((resolve) => {
|
|
505
507
|
const server = net.createServer();
|
|
506
508
|
server.once("error", () => resolve(false));
|
|
507
509
|
server.once("listening", () => {
|
|
508
510
|
server.close(() => resolve(true));
|
|
509
511
|
});
|
|
510
|
-
server.listen(port,
|
|
512
|
+
server.listen(port, host);
|
|
511
513
|
});
|
|
512
514
|
}
|
|
515
|
+
async function isPortFree(port) {
|
|
516
|
+
const free0 = await tryBind(port, "0.0.0.0");
|
|
517
|
+
if (!free0) return false;
|
|
518
|
+
const free1 = await tryBind(port, "127.0.0.1");
|
|
519
|
+
return free1;
|
|
520
|
+
}
|
|
521
|
+
async function getPortBlocker(port) {
|
|
522
|
+
try {
|
|
523
|
+
const { stdout } = await execa("lsof", ["-i", `:${port}`, "-t", "-sTCP:LISTEN"], { env: scrubEnv() });
|
|
524
|
+
const pid = parseInt(stdout.trim().split("\n")[0], 10);
|
|
525
|
+
if (!pid) return null;
|
|
526
|
+
try {
|
|
527
|
+
const { stdout: psOut } = await execa("ps", ["-p", String(pid), "-o", "comm="], { env: scrubEnv() });
|
|
528
|
+
return { port, pid, process: psOut.trim() };
|
|
529
|
+
} catch {
|
|
530
|
+
return { port, pid, process: "unknown" };
|
|
531
|
+
}
|
|
532
|
+
} catch {
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
513
536
|
async function findFreePort(preferred, max = 20) {
|
|
514
537
|
for (let offset = 0; offset < max; offset++) {
|
|
515
|
-
|
|
516
|
-
if (await isPortFree(port)) return port;
|
|
538
|
+
if (await isPortFree(preferred + offset)) return preferred + offset;
|
|
517
539
|
}
|
|
518
540
|
throw new Error(`No free port found near ${preferred}`);
|
|
519
541
|
}
|
|
542
|
+
async function resolvePortConflicts(ports) {
|
|
543
|
+
const labels = { ssh: "SSH", http: "HTTP", https: "HTTPS" };
|
|
544
|
+
const resolved2 = { ...ports };
|
|
545
|
+
for (const [key, port] of Object.entries(ports)) {
|
|
546
|
+
if (await isPortFree(port)) continue;
|
|
547
|
+
const blocker = await getPortBlocker(port);
|
|
548
|
+
const desc = blocker ? `${blocker.process} (PID ${blocker.pid})` : "unknown process";
|
|
549
|
+
const altPort = await findFreePort(port + 1).catch(() => null);
|
|
550
|
+
const choices = [];
|
|
551
|
+
if (blocker) {
|
|
552
|
+
choices.push({
|
|
553
|
+
name: `Kill ${desc} and use port ${port}`,
|
|
554
|
+
value: "kill"
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
if (altPort) {
|
|
558
|
+
choices.push({
|
|
559
|
+
name: `Use alternate port ${altPort} instead`,
|
|
560
|
+
value: "alt"
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
choices.push({ name: "Abort init", value: "abort" });
|
|
564
|
+
console.log("");
|
|
565
|
+
console.log(chalk5.yellow(` \u26A0 Port ${port} (${labels[key]}) is in use by ${desc}`));
|
|
566
|
+
const action = await select({
|
|
567
|
+
message: `How would you like to resolve the ${labels[key]} port conflict?`,
|
|
568
|
+
choices
|
|
569
|
+
});
|
|
570
|
+
if (action === "kill" && blocker) {
|
|
571
|
+
try {
|
|
572
|
+
process.kill(blocker.pid, "SIGTERM");
|
|
573
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
574
|
+
if (!await isPortFree(port)) {
|
|
575
|
+
process.kill(blocker.pid, "SIGKILL");
|
|
576
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
577
|
+
}
|
|
578
|
+
console.log(chalk5.green(` \u2713 Killed ${desc}, port ${port} is now free`));
|
|
579
|
+
} catch {
|
|
580
|
+
console.log(chalk5.red(` \u2717 Failed to kill PID ${blocker.pid}. Try: sudo kill ${blocker.pid}`));
|
|
581
|
+
process.exit(1);
|
|
582
|
+
}
|
|
583
|
+
} else if (action === "alt" && altPort) {
|
|
584
|
+
resolved2[key] = altPort;
|
|
585
|
+
console.log(chalk5.green(` \u2713 Using port ${altPort} for ${labels[key]}`));
|
|
586
|
+
} else {
|
|
587
|
+
console.log(chalk5.dim(" Init aborted."));
|
|
588
|
+
process.exit(0);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
return resolved2;
|
|
592
|
+
}
|
|
520
593
|
async function launchVm(platform, diskPath, initIsoPath, ram, cpus, ports) {
|
|
521
|
-
const resolved = {
|
|
522
|
-
ssh: await findFreePort(ports.ssh),
|
|
523
|
-
http: await findFreePort(ports.http),
|
|
524
|
-
https: await findFreePort(ports.https)
|
|
525
|
-
};
|
|
526
594
|
const machineArg = platform.os === "mac" ? "-machine virt,gic-version=3" : "-machine pc";
|
|
527
595
|
const biosArgs = fs3.existsSync(platform.biosPath) ? ["-bios", platform.biosPath] : [];
|
|
528
596
|
const args = [
|
|
@@ -1001,14 +1069,16 @@ var initCommand = new Command("init").description("Scaffold and launch a new NEX
|
|
|
1001
1069
|
const isoPath = await createCloudInitIso(userDataPath);
|
|
1002
1070
|
succeed(spinner, "Cloud-init ISO created");
|
|
1003
1071
|
showPhase(6, TOTAL_PHASES, "VM Launch");
|
|
1072
|
+
spinner = createSpinner("Checking port availability...");
|
|
1073
|
+
spinner.start();
|
|
1074
|
+
const requestedPorts = { ssh: config.sshPort, http: config.httpPort, https: config.httpsPort };
|
|
1075
|
+
spinner.stop();
|
|
1076
|
+
spinner.clear();
|
|
1077
|
+
const resolvedPorts = await resolvePortConflicts(requestedPorts);
|
|
1004
1078
|
spinner = createSpinner("Creating disk and launching VM...");
|
|
1005
1079
|
spinner.start();
|
|
1006
1080
|
const diskPath = await createDisk(imagePath, config.vmDisk);
|
|
1007
|
-
|
|
1008
|
-
ssh: config.sshPort,
|
|
1009
|
-
http: config.httpPort,
|
|
1010
|
-
https: config.httpsPort
|
|
1011
|
-
});
|
|
1081
|
+
await launchVm(platform, diskPath, isoPath, config.vmRam, config.vmCpus, resolvedPorts);
|
|
1012
1082
|
config.sshPort = resolvedPorts.ssh;
|
|
1013
1083
|
config.httpPort = resolvedPorts.http;
|
|
1014
1084
|
config.httpsPort = resolvedPorts.https;
|
|
@@ -1185,7 +1255,7 @@ var stopCommand = new Command3("stop").description("Gracefully shut down the NEX
|
|
|
1185
1255
|
|
|
1186
1256
|
// src/commands/status.ts
|
|
1187
1257
|
import { Command as Command4 } from "commander";
|
|
1188
|
-
import
|
|
1258
|
+
import chalk6 from "chalk";
|
|
1189
1259
|
var statusCommand = new Command4("status").description("Check NEXUS runtime health").option("--json", "Output as JSON").action(async (opts) => {
|
|
1190
1260
|
const config = loadConfig();
|
|
1191
1261
|
if (!config) {
|
|
@@ -1198,15 +1268,15 @@ var statusCommand = new Command4("status").description("Check NEXUS runtime heal
|
|
|
1198
1268
|
console.log(JSON.stringify({ ...health, pid: getVmPid(), ports: { ssh: config.sshPort, http: config.httpPort, https: config.httpsPort } }, null, 2));
|
|
1199
1269
|
return;
|
|
1200
1270
|
}
|
|
1201
|
-
const check = (ok) => ok ?
|
|
1271
|
+
const check = (ok) => ok ? chalk6.green("\u25CF") : chalk6.red("\u25CB");
|
|
1202
1272
|
console.log("");
|
|
1203
|
-
console.log(
|
|
1273
|
+
console.log(chalk6.bold(" NEXUS Runtime Status"));
|
|
1204
1274
|
console.log("");
|
|
1205
|
-
console.log(` ${check(health.vmRunning)} VM ${health.vmRunning ?
|
|
1206
|
-
console.log(` ${check(health.sshReady)} SSH ${health.sshReady ?
|
|
1207
|
-
console.log(` ${check(health.dockerReady)} Docker ${health.dockerReady ?
|
|
1208
|
-
console.log(` ${check(health.serverHealthy)} Server ${health.serverHealthy ?
|
|
1209
|
-
console.log(` ${check(!!health.tunnelUrl)} Tunnel ${health.tunnelUrl ?
|
|
1275
|
+
console.log(` ${check(health.vmRunning)} VM ${health.vmRunning ? chalk6.green("running") + chalk6.dim(` (PID ${getVmPid()})`) : chalk6.red("stopped")}`);
|
|
1276
|
+
console.log(` ${check(health.sshReady)} SSH ${health.sshReady ? chalk6.green("connected") + chalk6.dim(` (port ${config.sshPort})`) : chalk6.red("unreachable")}`);
|
|
1277
|
+
console.log(` ${check(health.dockerReady)} Docker ${health.dockerReady ? chalk6.green("ready") : chalk6.red("not ready")}`);
|
|
1278
|
+
console.log(` ${check(health.serverHealthy)} Server ${health.serverHealthy ? chalk6.green("healthy") + chalk6.dim(` (port ${config.httpPort})`) : chalk6.red("unhealthy")}`);
|
|
1279
|
+
console.log(` ${check(!!health.tunnelUrl)} Tunnel ${health.tunnelUrl ? chalk6.green(health.tunnelUrl) : chalk6.dim("not active")}`);
|
|
1210
1280
|
console.log("");
|
|
1211
1281
|
if (health.serverHealthy) {
|
|
1212
1282
|
log.success(`NEXUS CLI ready \u2014 connect via: buildwithnexus ssh`);
|
|
@@ -1215,18 +1285,18 @@ var statusCommand = new Command4("status").description("Check NEXUS runtime heal
|
|
|
1215
1285
|
|
|
1216
1286
|
// src/commands/doctor.ts
|
|
1217
1287
|
import { Command as Command5 } from "commander";
|
|
1218
|
-
import
|
|
1288
|
+
import chalk7 from "chalk";
|
|
1219
1289
|
import fs7 from "fs";
|
|
1220
1290
|
import path8 from "path";
|
|
1221
1291
|
import { execa as execa4 } from "execa";
|
|
1222
1292
|
var doctorCommand = new Command5("doctor").description("Diagnose NEXUS runtime environment").action(async () => {
|
|
1223
1293
|
const platform = detectPlatform();
|
|
1224
|
-
const check = (ok) => ok ?
|
|
1294
|
+
const check = (ok) => ok ? chalk7.green("\u2713") : chalk7.red("\u2717");
|
|
1225
1295
|
console.log("");
|
|
1226
|
-
console.log(
|
|
1296
|
+
console.log(chalk7.bold(" NEXUS Doctor"));
|
|
1227
1297
|
console.log("");
|
|
1228
1298
|
const nodeOk = Number(process.versions.node.split(".")[0]) >= 18;
|
|
1229
|
-
console.log(` ${check(nodeOk)} Node.js ${process.versions.node} ${nodeOk ? "" :
|
|
1299
|
+
console.log(` ${check(nodeOk)} Node.js ${process.versions.node} ${nodeOk ? "" : chalk7.red("(need >= 18)")}`);
|
|
1230
1300
|
console.log(` ${check(true)} Platform: ${platform.os} ${platform.arch}`);
|
|
1231
1301
|
const qemuOk = await isQemuInstalled(platform);
|
|
1232
1302
|
if (qemuOk) {
|
|
@@ -1266,14 +1336,14 @@ var doctorCommand = new Command5("doctor").description("Diagnose NEXUS runtime e
|
|
|
1266
1336
|
});
|
|
1267
1337
|
server.listen(port);
|
|
1268
1338
|
});
|
|
1269
|
-
console.log(` ${check(available)} Port ${port} (${name}) ${available ? "available" :
|
|
1339
|
+
console.log(` ${check(available)} Port ${port} (${name}) ${available ? "available" : chalk7.red("in use")}`);
|
|
1270
1340
|
} catch {
|
|
1271
1341
|
console.log(` ${check(false)} Port ${port} (${name}) \u2014 check failed`);
|
|
1272
1342
|
}
|
|
1273
1343
|
}
|
|
1274
1344
|
}
|
|
1275
1345
|
const biosOk = fs7.existsSync(platform.biosPath);
|
|
1276
|
-
console.log(` ${check(biosOk)} UEFI firmware ${biosOk ? "" :
|
|
1346
|
+
console.log(` ${check(biosOk)} UEFI firmware ${biosOk ? "" : chalk7.dim(platform.biosPath)}`);
|
|
1277
1347
|
console.log("");
|
|
1278
1348
|
if (qemuOk && isoTool && biosOk) {
|
|
1279
1349
|
log.success("Environment ready for NEXUS");
|
|
@@ -1377,7 +1447,7 @@ var updateCommand = new Command7("update").description("Update NEXUS to the late
|
|
|
1377
1447
|
|
|
1378
1448
|
// src/commands/destroy.ts
|
|
1379
1449
|
import { Command as Command8 } from "commander";
|
|
1380
|
-
import
|
|
1450
|
+
import chalk8 from "chalk";
|
|
1381
1451
|
import fs9 from "fs";
|
|
1382
1452
|
import { input as input2 } from "@inquirer/prompts";
|
|
1383
1453
|
import path10 from "path";
|
|
@@ -1385,11 +1455,11 @@ var destroyCommand = new Command8("destroy").description("Remove NEXUS VM and al
|
|
|
1385
1455
|
const config = loadConfig();
|
|
1386
1456
|
if (!opts.force) {
|
|
1387
1457
|
console.log("");
|
|
1388
|
-
console.log(
|
|
1389
|
-
console.log(
|
|
1390
|
-
console.log(
|
|
1391
|
-
console.log(
|
|
1392
|
-
console.log(
|
|
1458
|
+
console.log(chalk8.red.bold(" This will permanently delete:"));
|
|
1459
|
+
console.log(chalk8.red(" - NEXUS VM and all data inside it"));
|
|
1460
|
+
console.log(chalk8.red(" - VM disk images"));
|
|
1461
|
+
console.log(chalk8.red(" - SSH keys"));
|
|
1462
|
+
console.log(chalk8.red(" - Configuration and API keys"));
|
|
1393
1463
|
console.log("");
|
|
1394
1464
|
const confirm2 = await input2({
|
|
1395
1465
|
message: 'Type "destroy" to confirm:'
|
|
@@ -1433,7 +1503,7 @@ var destroyCommand = new Command8("destroy").description("Remove NEXUS VM and al
|
|
|
1433
1503
|
// src/commands/keys.ts
|
|
1434
1504
|
import { Command as Command9 } from "commander";
|
|
1435
1505
|
import { password as password2 } from "@inquirer/prompts";
|
|
1436
|
-
import
|
|
1506
|
+
import chalk9 from "chalk";
|
|
1437
1507
|
var keysCommand = new Command9("keys").description("Manage API keys");
|
|
1438
1508
|
keysCommand.command("list").description("Show configured API keys (masked)").action(() => {
|
|
1439
1509
|
const keys = loadKeys();
|
|
@@ -1441,10 +1511,10 @@ keysCommand.command("list").description("Show configured API keys (masked)").act
|
|
|
1441
1511
|
log.error("No keys configured. Run: buildwithnexus init");
|
|
1442
1512
|
process.exit(1);
|
|
1443
1513
|
}
|
|
1444
|
-
console.log(
|
|
1514
|
+
console.log(chalk9.bold("\n Configured Keys\n"));
|
|
1445
1515
|
for (const [name, value] of Object.entries(keys)) {
|
|
1446
1516
|
if (value) {
|
|
1447
|
-
console.log(` ${
|
|
1517
|
+
console.log(` ${chalk9.cyan(name.padEnd(24))} ${maskKey(value)}`);
|
|
1448
1518
|
}
|
|
1449
1519
|
}
|
|
1450
1520
|
console.log("");
|
|
@@ -1506,14 +1576,14 @@ var sshCommand = new Command10("ssh").description("Open an SSH session into the
|
|
|
1506
1576
|
|
|
1507
1577
|
// src/commands/brainstorm.ts
|
|
1508
1578
|
import { Command as Command11 } from "commander";
|
|
1509
|
-
import
|
|
1579
|
+
import chalk10 from "chalk";
|
|
1510
1580
|
import { input as input3 } from "@inquirer/prompts";
|
|
1511
|
-
var COS_PREFIX =
|
|
1512
|
-
var YOU_PREFIX =
|
|
1513
|
-
var DIVIDER =
|
|
1581
|
+
var COS_PREFIX = chalk10.bold.cyan(" Chief of Staff");
|
|
1582
|
+
var YOU_PREFIX = chalk10.bold.white(" You");
|
|
1583
|
+
var DIVIDER = chalk10.dim(" " + "\u2500".repeat(56));
|
|
1514
1584
|
function formatResponse(text) {
|
|
1515
1585
|
const lines = text.split("\n");
|
|
1516
|
-
return lines.map((line) =>
|
|
1586
|
+
return lines.map((line) => chalk10.white(" " + line)).join("\n");
|
|
1517
1587
|
}
|
|
1518
1588
|
async function sendMessage(sshPort, message, source) {
|
|
1519
1589
|
const payload = JSON.stringify({ message, source });
|
|
@@ -1556,13 +1626,13 @@ var brainstormCommand = new Command11("brainstorm").description("Brainstorm an i
|
|
|
1556
1626
|
}
|
|
1557
1627
|
succeed(spinner, "Connected to NEXUS");
|
|
1558
1628
|
console.log("");
|
|
1559
|
-
console.log(
|
|
1560
|
-
console.log(
|
|
1561
|
-
console.log(
|
|
1562
|
-
console.log(
|
|
1563
|
-
console.log(
|
|
1564
|
-
console.log(
|
|
1565
|
-
console.log(
|
|
1629
|
+
console.log(chalk10.bold(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
|
|
1630
|
+
console.log(chalk10.bold(" \u2551 ") + chalk10.bold.cyan("NEXUS Brainstorm Session") + chalk10.bold(" \u2551"));
|
|
1631
|
+
console.log(chalk10.bold(" \u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"));
|
|
1632
|
+
console.log(chalk10.bold(" \u2551 ") + chalk10.dim("The Chief of Staff will discuss your idea with the".padEnd(55)) + chalk10.bold("\u2551"));
|
|
1633
|
+
console.log(chalk10.bold(" \u2551 ") + chalk10.dim("NEXUS team and share their recommendations.".padEnd(55)) + chalk10.bold("\u2551"));
|
|
1634
|
+
console.log(chalk10.bold(" \u2551 ") + chalk10.dim("Type 'exit' or 'quit' to end the session.".padEnd(55)) + chalk10.bold("\u2551"));
|
|
1635
|
+
console.log(chalk10.bold(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
|
|
1566
1636
|
console.log("");
|
|
1567
1637
|
let idea = ideaWords.length > 0 ? ideaWords.join(" ") : "";
|
|
1568
1638
|
if (!idea) {
|
|
@@ -1579,7 +1649,7 @@ var brainstormCommand = new Command11("brainstorm").description("Brainstorm an i
|
|
|
1579
1649
|
while (true) {
|
|
1580
1650
|
turn++;
|
|
1581
1651
|
if (turn === 1) {
|
|
1582
|
-
console.log(`${YOU_PREFIX}: ${
|
|
1652
|
+
console.log(`${YOU_PREFIX}: ${chalk10.white(idea)}`);
|
|
1583
1653
|
}
|
|
1584
1654
|
console.log(DIVIDER);
|
|
1585
1655
|
const thinking = createSpinner(
|
|
@@ -1597,17 +1667,17 @@ var brainstormCommand = new Command11("brainstorm").description("Brainstorm an i
|
|
|
1597
1667
|
console.log(formatResponse(redact(response)));
|
|
1598
1668
|
console.log(DIVIDER);
|
|
1599
1669
|
const followUp = await input3({
|
|
1600
|
-
message:
|
|
1670
|
+
message: chalk10.bold("You:")
|
|
1601
1671
|
});
|
|
1602
1672
|
const trimmed = followUp.trim().toLowerCase();
|
|
1603
1673
|
if (!trimmed || trimmed === "exit" || trimmed === "quit" || trimmed === "q") {
|
|
1604
1674
|
console.log("");
|
|
1605
1675
|
log.success("Brainstorm session ended");
|
|
1606
|
-
console.log(
|
|
1676
|
+
console.log(chalk10.dim(" Run again anytime: buildwithnexus brainstorm"));
|
|
1607
1677
|
console.log("");
|
|
1608
1678
|
return;
|
|
1609
1679
|
}
|
|
1610
|
-
console.log(`${YOU_PREFIX}: ${
|
|
1680
|
+
console.log(`${YOU_PREFIX}: ${chalk10.white(followUp)}`);
|
|
1611
1681
|
currentMessage = `[BRAINSTORM FOLLOW-UP] The CEO responds: ${followUp}`;
|
|
1612
1682
|
}
|
|
1613
1683
|
} catch (err) {
|
|
@@ -1623,7 +1693,7 @@ var brainstormCommand = new Command11("brainstorm").description("Brainstorm an i
|
|
|
1623
1693
|
});
|
|
1624
1694
|
|
|
1625
1695
|
// src/cli.ts
|
|
1626
|
-
var cli = new Command12().name("buildwithnexus").description("Auto-scaffold and launch a fully autonomous NEXUS runtime").version("0.2.
|
|
1696
|
+
var cli = new Command12().name("buildwithnexus").description("Auto-scaffold and launch a fully autonomous NEXUS runtime").version("0.2.6");
|
|
1627
1697
|
cli.addCommand(initCommand);
|
|
1628
1698
|
cli.addCommand(startCommand);
|
|
1629
1699
|
cli.addCommand(stopCommand);
|
|
@@ -1644,7 +1714,7 @@ import fs10 from "fs";
|
|
|
1644
1714
|
import path11 from "path";
|
|
1645
1715
|
import os3 from "os";
|
|
1646
1716
|
import https from "https";
|
|
1647
|
-
import
|
|
1717
|
+
import chalk11 from "chalk";
|
|
1648
1718
|
var PACKAGE_NAME = "buildwithnexus";
|
|
1649
1719
|
var CHECK_INTERVAL_MS = 4 * 60 * 60 * 1e3;
|
|
1650
1720
|
var STATE_DIR = path11.join(os3.homedir(), ".buildwithnexus");
|
|
@@ -1725,8 +1795,8 @@ async function checkForUpdates(currentVersion) {
|
|
|
1725
1795
|
function printUpdateBanner(current, latest) {
|
|
1726
1796
|
const msg = [
|
|
1727
1797
|
"",
|
|
1728
|
-
|
|
1729
|
-
|
|
1798
|
+
chalk11.yellow(` Update available: ${current} \u2192 ${latest}`),
|
|
1799
|
+
chalk11.cyan(` Run: npm update -g buildwithnexus`),
|
|
1730
1800
|
""
|
|
1731
1801
|
].join("\n");
|
|
1732
1802
|
process.stderr.write(msg + "\n");
|
|
Binary file
|