buildwithnexus 0.3.1 → 0.3.3

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 CHANGED
@@ -363,7 +363,7 @@ __export(qemu_exports, {
363
363
  import fs3 from "fs";
364
364
  import net from "net";
365
365
  import path3 from "path";
366
- import { execa } from "execa";
366
+ import { execa, execaSync } from "execa";
367
367
  import { select } from "@inquirer/prompts";
368
368
  import chalk5 from "chalk";
369
369
  async function isQemuInstalled(platform) {
@@ -378,10 +378,16 @@ async function installQemu(platform) {
378
378
  if (platform.os === "mac") {
379
379
  await execa("brew", ["install", "qemu", "cdrtools"], { stdio: "inherit", env: scrubEnv() });
380
380
  } else if (platform.os === "linux") {
381
+ let hasApt = false;
381
382
  try {
383
+ await execa("which", ["apt-get"], { env: scrubEnv() });
384
+ hasApt = true;
385
+ } catch {
386
+ }
387
+ if (hasApt) {
382
388
  await execa("sudo", ["apt-get", "update"], { stdio: "inherit", env: scrubEnv() });
383
389
  await execa("sudo", ["apt-get", "install", "-y", "qemu-system", "qemu-utils", "genisoimage"], { stdio: "inherit", env: scrubEnv() });
384
- } catch {
390
+ } else {
385
391
  await execa("sudo", ["yum", "install", "-y", "qemu-system-arm", "qemu-system-x86", "qemu-img", "genisoimage"], { stdio: "inherit", env: scrubEnv() });
386
392
  }
387
393
  } else {
@@ -392,7 +398,7 @@ async function downloadImage(platform) {
392
398
  const imagePath = path3.join(IMAGES_DIR, platform.ubuntuImage);
393
399
  if (fs3.existsSync(imagePath)) return imagePath;
394
400
  const url = `${UBUNTU_BASE_URL}/${platform.ubuntuImage}`;
395
- await execa("curl", ["-L", "-o", imagePath, "--progress-bar", url], { stdio: "inherit", env: scrubEnv() });
401
+ await execa("curl", ["-L", "-C", "-", "-o", imagePath, "--progress-bar", url], { stdio: "inherit", env: scrubEnv() });
396
402
  return imagePath;
397
403
  }
398
404
  async function createDisk(basePath, sizeGb) {
@@ -490,38 +496,36 @@ async function resolvePortConflicts(ports) {
490
496
  return resolved;
491
497
  }
492
498
  async function launchVm(platform, diskPath, initIsoPath, ram, cpus, ports) {
493
- const machineArg = platform.os === "mac" ? "-machine virt,gic-version=3" : "-machine pc";
499
+ const machineArgs = platform.os === "mac" ? ["-machine", "virt,gic-version=3"] : ["-machine", "pc"];
494
500
  const biosArgs = fs3.existsSync(platform.biosPath) ? ["-bios", platform.biosPath] : [];
495
- function buildArgs(cpuFlag) {
496
- return [
497
- ...machineArg.split(" "),
498
- ...cpuFlag.split(" "),
499
- "-m",
500
- `${ram}G`,
501
- "-smp",
502
- `${cpus}`,
503
- "-drive",
504
- `file=${diskPath},if=virtio,cache=writethrough`,
505
- "-drive",
506
- `file=${initIsoPath},if=virtio,format=raw,cache=writethrough`,
507
- "-display",
508
- "none",
509
- "-serial",
510
- "none",
511
- "-net",
512
- "nic,model=virtio",
513
- "-net",
514
- `user,hostfwd=tcp::${ports.ssh}-:22,hostfwd=tcp::${ports.http}-:4200,hostfwd=tcp::${ports.https}-:443`,
515
- ...biosArgs,
516
- "-pidfile",
517
- PID_FILE,
518
- "-daemonize"
519
- ];
520
- }
501
+ const buildArgs = (cpuArgs) => [
502
+ ...machineArgs,
503
+ ...cpuArgs,
504
+ "-m",
505
+ `${ram}G`,
506
+ "-smp",
507
+ `${cpus}`,
508
+ "-drive",
509
+ `file=${diskPath},if=virtio,cache=writethrough`,
510
+ "-drive",
511
+ `file=${initIsoPath},if=virtio,format=raw,cache=writethrough`,
512
+ "-display",
513
+ "none",
514
+ "-serial",
515
+ "none",
516
+ "-net",
517
+ "nic,model=virtio",
518
+ "-net",
519
+ `user,hostfwd=tcp::${ports.ssh}-:22,hostfwd=tcp::${ports.http}-:4200,hostfwd=tcp::${ports.https}-:443`,
520
+ ...biosArgs,
521
+ "-pidfile",
522
+ PID_FILE,
523
+ "-daemonize"
524
+ ];
521
525
  try {
522
- await execa(platform.qemuBinary, buildArgs(platform.qemuCpuFlag), { env: scrubEnv() });
526
+ await execa(platform.qemuBinary, buildArgs(platform.qemuCpuFlag.split(" ")), { env: scrubEnv() });
523
527
  } catch {
524
- const fallbackCpu = platform.os === "mac" ? "-cpu max" : "-cpu qemu64";
528
+ const fallbackCpu = platform.os === "mac" ? ["-cpu", "max"] : ["-cpu", "qemu64"];
525
529
  await execa(platform.qemuBinary, buildArgs(fallbackCpu), { env: scrubEnv() });
526
530
  }
527
531
  return ports;
@@ -533,6 +537,14 @@ function readValidPid() {
533
537
  if (!Number.isInteger(pid) || pid <= 1 || pid > 4194304) return null;
534
538
  return pid;
535
539
  }
540
+ function isQemuPid(pid) {
541
+ try {
542
+ const { stdout } = execaSync("ps", ["-p", String(pid), "-o", "comm="], { env: scrubEnv() });
543
+ return stdout.trim().toLowerCase().includes("qemu");
544
+ } catch {
545
+ return false;
546
+ }
547
+ }
536
548
  function isVmRunning() {
537
549
  const pid = readValidPid();
538
550
  if (!pid) return false;
@@ -546,6 +558,13 @@ function isVmRunning() {
546
558
  function stopVm() {
547
559
  const pid = readValidPid();
548
560
  if (!pid) return;
561
+ if (!isQemuPid(pid)) {
562
+ try {
563
+ fs3.unlinkSync(PID_FILE);
564
+ } catch {
565
+ }
566
+ return;
567
+ }
549
568
  try {
550
569
  process.kill(pid, "SIGTERM");
551
570
  } catch {
@@ -722,6 +741,7 @@ import { Command as Command14 } from "commander";
722
741
  // src/commands/init.ts
723
742
  init_banner();
724
743
  import { Command } from "commander";
744
+ import chalk6 from "chalk";
725
745
 
726
746
  // src/ui/spinner.ts
727
747
  import ora from "ora";
@@ -928,69 +948,65 @@ async function createCloudInitIso(userDataPath) {
928
948
  fs5.writeFileSync(metaDataPath, "instance-id: nexus-vm-1\nlocal-hostname: nexus-vm\n", { mode: 384 });
929
949
  const isoPath = path5.join(IMAGES_DIR2, "init.iso");
930
950
  const env = scrubEnv();
931
- let created = false;
932
951
  try {
933
- await execa3("mkisofs", [
934
- "-output",
935
- isoPath,
936
- "-volid",
937
- "cidata",
938
- "-joliet",
939
- "-rock",
940
- userDataPath,
941
- metaDataPath
942
- ], { env });
943
- created = true;
944
- } catch {
945
- }
946
- if (!created) {
952
+ let created = false;
953
+ for (const tool of ["mkisofs", "genisoimage"]) {
954
+ if (created) break;
955
+ try {
956
+ await execa3(tool, [
957
+ "-output",
958
+ isoPath,
959
+ "-volid",
960
+ "cidata",
961
+ "-joliet",
962
+ "-rock",
963
+ userDataPath,
964
+ metaDataPath
965
+ ], { env });
966
+ created = true;
967
+ } catch {
968
+ }
969
+ }
970
+ if (!created) {
971
+ try {
972
+ const stagingDir = path5.join(CONFIGS_DIR, "cidata-staging");
973
+ fs5.mkdirSync(stagingDir, { recursive: true, mode: 448 });
974
+ fs5.copyFileSync(userDataPath, path5.join(stagingDir, "user-data"));
975
+ fs5.copyFileSync(metaDataPath, path5.join(stagingDir, "meta-data"));
976
+ await execa3("hdiutil", [
977
+ "makehybrid",
978
+ "-o",
979
+ isoPath,
980
+ "-joliet",
981
+ "-iso",
982
+ "-default-volume-name",
983
+ "cidata",
984
+ stagingDir
985
+ ], { env });
986
+ fs5.rmSync(stagingDir, { recursive: true, force: true });
987
+ created = true;
988
+ } catch {
989
+ }
990
+ }
991
+ if (!created) {
992
+ throw new Error(
993
+ "Cannot create cloud-init ISO: none of mkisofs, genisoimage, or hdiutil are available. On macOS, install cdrtools: brew install cdrtools. On Linux: sudo apt install genisoimage"
994
+ );
995
+ }
996
+ fs5.chmodSync(isoPath, 384);
997
+ audit("cloudinit_iso_created", "init.iso created");
998
+ return isoPath;
999
+ } finally {
947
1000
  try {
948
- await execa3("genisoimage", [
949
- "-output",
950
- isoPath,
951
- "-volid",
952
- "cidata",
953
- "-joliet",
954
- "-rock",
955
- userDataPath,
956
- metaDataPath
957
- ], { env });
958
- created = true;
1001
+ fs5.unlinkSync(userDataPath);
959
1002
  } catch {
960
1003
  }
961
- }
962
- if (!created) {
963
1004
  try {
964
- const stagingDir = path5.join(CONFIGS_DIR, "cidata-staging");
965
- fs5.mkdirSync(stagingDir, { recursive: true, mode: 448 });
966
- fs5.copyFileSync(userDataPath, path5.join(stagingDir, "user-data"));
967
- fs5.copyFileSync(metaDataPath, path5.join(stagingDir, "meta-data"));
968
- await execa3("hdiutil", [
969
- "makehybrid",
970
- "-o",
971
- isoPath,
972
- "-joliet",
973
- "-iso",
974
- "-default-volume-name",
975
- "cidata",
976
- stagingDir
977
- ], { env });
978
- fs5.rmSync(stagingDir, { recursive: true, force: true });
979
- created = true;
1005
+ fs5.unlinkSync(metaDataPath);
980
1006
  } catch {
981
1007
  }
1008
+ audit("cloudinit_plaintext_deleted", "user-data.yaml and meta-data.yaml removed");
982
1009
  }
983
- if (!created) {
984
- throw new Error(
985
- "Cannot create cloud-init ISO: none of mkisofs, genisoimage, or hdiutil are available. On macOS, install cdrtools: brew install cdrtools. On Linux: sudo apt install genisoimage"
986
- );
987
- }
988
- fs5.chmodSync(isoPath, 384);
989
- fs5.unlinkSync(userDataPath);
990
- fs5.unlinkSync(metaDataPath);
991
- audit("cloudinit_plaintext_deleted", "user-data.yaml and meta-data.yaml removed");
992
- audit("cloudinit_iso_created", "init.iso created");
993
- return isoPath;
994
1010
  }
995
1011
 
996
1012
  // src/core/health.ts
@@ -1029,27 +1045,51 @@ async function checkHealth(port, vmRunning) {
1029
1045
  }
1030
1046
  return status;
1031
1047
  }
1032
- async function waitForServer(port, timeoutMs = 6e5) {
1048
+ async function waitForServer(port, timeoutMs = 9e5) {
1033
1049
  const start = Date.now();
1050
+ let lastLog = 0;
1034
1051
  while (Date.now() - start < timeoutMs) {
1035
1052
  try {
1036
1053
  const { stdout, code } = await sshExec(port, "curl -sf http://localhost:4200/health");
1037
1054
  if (code === 0 && stdout.includes("ok")) return true;
1038
1055
  } catch {
1039
1056
  }
1040
- await new Promise((r) => setTimeout(r, 1e4));
1057
+ const elapsed = Date.now() - start;
1058
+ if (elapsed - lastLog >= 3e4) {
1059
+ lastLog = elapsed;
1060
+ try {
1061
+ const { stdout } = await sshExec(port, "systemctl is-active nexus 2>/dev/null || echo 'starting...'");
1062
+ process.stderr.write(`
1063
+ [server ${Math.round(elapsed / 1e3)}s] ${stdout.trim().slice(0, 120)}
1064
+ `);
1065
+ } catch {
1066
+ }
1067
+ }
1068
+ await new Promise((r) => setTimeout(r, 5e3));
1041
1069
  }
1042
1070
  return false;
1043
1071
  }
1044
- async function waitForCloudInit(port, timeoutMs = 9e5) {
1072
+ async function waitForCloudInit(port, timeoutMs = 18e5) {
1045
1073
  const start = Date.now();
1074
+ let lastLog = 0;
1046
1075
  while (Date.now() - start < timeoutMs) {
1047
1076
  try {
1048
1077
  const { code } = await sshExec(port, "test -f /var/lib/cloud/instance/boot-finished");
1049
1078
  if (code === 0) return true;
1050
1079
  } catch {
1051
1080
  }
1052
- await new Promise((r) => setTimeout(r, 1e4));
1081
+ const elapsed = Date.now() - start;
1082
+ if (elapsed - lastLog >= 6e4) {
1083
+ lastLog = elapsed;
1084
+ try {
1085
+ const { stdout } = await sshExec(port, "tail -1 /var/log/cloud-init-output.log 2>/dev/null || echo 'waiting...'");
1086
+ process.stderr.write(`
1087
+ [cloud-init ${Math.round(elapsed / 1e3)}s] ${stdout.trim().slice(0, 120)}
1088
+ `);
1089
+ } catch {
1090
+ }
1091
+ }
1092
+ await new Promise((r) => setTimeout(r, 2e4));
1053
1093
  }
1054
1094
  return false;
1055
1095
  }
@@ -1076,17 +1116,19 @@ async function installCloudflared(sshPort, arch) {
1076
1116
  }
1077
1117
  async function startTunnel(sshPort) {
1078
1118
  await sshExec(sshPort, [
1079
- "nohup cloudflared tunnel --url http://localhost:4200",
1080
- "> /tmp/tunnel.log 2>&1 &",
1119
+ "install -m 600 /dev/null /home/nexus/.nexus/tunnel.log",
1120
+ "&& nohup cloudflared tunnel --no-autoupdate --url http://localhost:4200",
1121
+ "> /home/nexus/.nexus/tunnel.log 2>&1 &",
1081
1122
  "disown"
1082
1123
  ].join(" "));
1083
1124
  const start = Date.now();
1084
- while (Date.now() - start < 3e4) {
1125
+ while (Date.now() - start < 6e4) {
1085
1126
  try {
1086
- const { stdout } = await sshExec(sshPort, "grep -o 'https://[^ ]*\\.trycloudflare\\.com' /tmp/tunnel.log 2>/dev/null | head -1");
1127
+ const { stdout } = await sshExec(sshPort, "grep -oE 'https://[a-z0-9-]+\\.trycloudflare\\.com' /home/nexus/.nexus/tunnel.log 2>/dev/null | head -1");
1087
1128
  if (stdout.includes("https://")) {
1088
1129
  const url = stdout.trim();
1089
1130
  if (!/^https:\/\/[a-z0-9-]+\.trycloudflare\.com$/.test(url)) {
1131
+ audit("tunnel_url_rejected", `Invalid URL format: ${url.slice(0, 80)}`);
1090
1132
  return null;
1091
1133
  }
1092
1134
  await sshExec(sshPort, shellCommand`printf '%s\n' ${url} > /home/nexus/.nexus/tunnel-url.txt && chmod 600 /home/nexus/.nexus/tunnel-url.txt`);
@@ -1119,176 +1161,283 @@ function getReleaseTarball() {
1119
1161
  if (fs6.existsSync(rootPath)) return rootPath;
1120
1162
  throw new Error("nexus-release.tar.gz not found. Run: npm run bundle");
1121
1163
  }
1122
- var TOTAL_PHASES = 10;
1123
1164
  function getCloudInitTemplate() {
1124
1165
  const dir = path6.dirname(fileURLToPath(import.meta.url));
1125
1166
  const templatePath = path6.join(dir, "templates", "cloud-init.yaml.ejs");
1126
- if (fs6.existsSync(templatePath)) {
1127
- return fs6.readFileSync(templatePath, "utf-8");
1128
- }
1167
+ if (fs6.existsSync(templatePath)) return fs6.readFileSync(templatePath, "utf-8");
1129
1168
  const srcPath = path6.resolve(dir, "..", "src", "templates", "cloud-init.yaml.ejs");
1130
1169
  return fs6.readFileSync(srcPath, "utf-8");
1131
1170
  }
1132
- var initCommand = new Command("init").description("Scaffold and launch a new NEXUS runtime").action(async () => {
1133
- try {
1134
- showBanner();
1135
- showPhase(1, TOTAL_PHASES, "Configuration");
1136
- const platform = detectPlatform();
1137
- log.detail("Platform", `${platform.os} ${platform.arch}`);
1138
- log.detail("QEMU", platform.qemuBinary);
1139
- const userConfig = await promptInitConfig();
1140
- ensureHome();
1141
- const masterSecret = generateMasterSecret();
1142
- const config = {
1143
- vmRam: userConfig.vmRam,
1144
- vmCpus: userConfig.vmCpus,
1145
- vmDisk: userConfig.vmDisk,
1146
- enableTunnel: userConfig.enableTunnel,
1147
- sshPort: 2222,
1148
- httpPort: 4200,
1149
- httpsPort: 8443,
1150
- masterSecret
1151
- };
1152
- const keys = {
1153
- ANTHROPIC_API_KEY: userConfig.anthropicKey,
1154
- OPENAI_API_KEY: userConfig.openaiKey || void 0,
1155
- GOOGLE_API_KEY: userConfig.googleKey || void 0,
1156
- NEXUS_MASTER_SECRET: masterSecret
1157
- };
1158
- const violations = validateAllKeys(keys);
1159
- if (violations.length > 0) {
1160
- for (const v of violations) log.error(v);
1161
- process.exit(1);
1171
+ async function withSpinner(spinner, label, fn) {
1172
+ spinner.text = label;
1173
+ spinner.start();
1174
+ const result = await fn();
1175
+ succeed(spinner, label);
1176
+ return result;
1177
+ }
1178
+ var phases = [
1179
+ // Phase 1 — Configuration
1180
+ {
1181
+ name: "Configuration",
1182
+ run: async (ctx) => {
1183
+ showBanner();
1184
+ const platform = detectPlatform();
1185
+ log.detail("Platform", `${platform.os} ${platform.arch}`);
1186
+ log.detail("QEMU", platform.qemuBinary);
1187
+ const userConfig = await promptInitConfig();
1188
+ ensureHome();
1189
+ const masterSecret = generateMasterSecret();
1190
+ const config = {
1191
+ vmRam: userConfig.vmRam,
1192
+ vmCpus: userConfig.vmCpus,
1193
+ vmDisk: userConfig.vmDisk,
1194
+ enableTunnel: userConfig.enableTunnel,
1195
+ sshPort: 2222,
1196
+ httpPort: 4200,
1197
+ httpsPort: 8443,
1198
+ masterSecret
1199
+ };
1200
+ const keys = {
1201
+ ANTHROPIC_API_KEY: userConfig.anthropicKey,
1202
+ OPENAI_API_KEY: userConfig.openaiKey || void 0,
1203
+ GOOGLE_API_KEY: userConfig.googleKey || void 0,
1204
+ NEXUS_MASTER_SECRET: masterSecret
1205
+ };
1206
+ const violations = validateAllKeys(keys);
1207
+ if (violations.length > 0) {
1208
+ for (const v of violations) log.error(v);
1209
+ process.exit(1);
1210
+ }
1211
+ saveConfig(config);
1212
+ saveKeys(keys);
1213
+ log.success("Configuration saved");
1214
+ ctx.platform = platform;
1215
+ ctx.config = config;
1216
+ ctx.keys = keys;
1162
1217
  }
1163
- saveConfig(config);
1164
- saveKeys(keys);
1165
- log.success("Configuration saved");
1166
- showPhase(2, TOTAL_PHASES, "QEMU Installation");
1167
- let spinner = createSpinner("Checking QEMU...");
1168
- spinner.start();
1169
- const hasQemu = await isQemuInstalled(platform);
1170
- if (hasQemu) {
1171
- succeed(spinner, "QEMU already installed");
1172
- } else {
1173
- spinner.text = "Installing QEMU...";
1174
- await installQemu(platform);
1175
- succeed(spinner, "QEMU installed");
1218
+ },
1219
+ // Phase 2 — QEMU
1220
+ {
1221
+ name: "QEMU Installation",
1222
+ run: async (ctx, spinner) => {
1223
+ const { platform } = ctx;
1224
+ await withSpinner(spinner, "Checking QEMU...", async () => {
1225
+ const hasQemu = await isQemuInstalled(platform);
1226
+ if (!hasQemu) {
1227
+ spinner.text = "Installing QEMU...";
1228
+ await installQemu(platform);
1229
+ }
1230
+ });
1231
+ succeed(spinner, hasQemuLabel(await isQemuInstalled(ctx.platform)));
1176
1232
  }
1177
- showPhase(3, TOTAL_PHASES, "SSH Key Setup");
1178
- spinner = createSpinner("Generating SSH key...");
1179
- spinner.start();
1180
- await generateSshKey();
1181
- addSshConfig(config.sshPort);
1182
- succeed(spinner, "SSH key ready (ed25519)");
1183
- showPhase(4, TOTAL_PHASES, "VM Image Download");
1184
- spinner = createSpinner(`Downloading Ubuntu 24.04 (${platform.ubuntuImage})...`);
1185
- spinner.start();
1186
- const imagePath = await downloadImage(platform);
1187
- succeed(spinner, "Ubuntu image ready");
1188
- showPhase(5, TOTAL_PHASES, "Cloud-Init Generation");
1189
- spinner = createSpinner("Locating release tarball...");
1190
- spinner.start();
1191
- const tarballPath = getReleaseTarball();
1192
- succeed(spinner, `Release tarball found (${path6.basename(tarballPath)})`);
1193
- spinner = createSpinner("Rendering cloud-init...");
1194
- spinner.start();
1195
- const pubKey = getPubKey();
1196
- const template = getCloudInitTemplate();
1197
- const userDataPath = await renderCloudInit({ sshPubKey: pubKey, keys, config }, template);
1198
- const isoPath = await createCloudInitIso(userDataPath);
1199
- succeed(spinner, "Cloud-init ISO created");
1200
- showPhase(6, TOTAL_PHASES, "VM Launch");
1201
- spinner = createSpinner("Checking port availability...");
1202
- spinner.start();
1203
- const requestedPorts = { ssh: config.sshPort, http: config.httpPort, https: config.httpsPort };
1204
- spinner.stop();
1205
- spinner.clear();
1206
- const resolvedPorts = await resolvePortConflicts(requestedPorts);
1207
- spinner = createSpinner("Creating disk and launching VM...");
1208
- spinner.start();
1209
- const diskPath = await createDisk(imagePath, config.vmDisk);
1210
- await launchVm(platform, diskPath, isoPath, config.vmRam, config.vmCpus, resolvedPorts);
1211
- config.sshPort = resolvedPorts.ssh;
1212
- config.httpPort = resolvedPorts.http;
1213
- config.httpsPort = resolvedPorts.https;
1214
- saveConfig(config);
1215
- const portNote = resolvedPorts.ssh !== 2222 || resolvedPorts.http !== 4200 || resolvedPorts.https !== 8443 ? ` (ports: SSH=${resolvedPorts.ssh}, HTTP=${resolvedPorts.http}, HTTPS=${resolvedPorts.https})` : "";
1216
- succeed(spinner, `VM launched (daemonized)${portNote}`);
1217
- showPhase(7, TOTAL_PHASES, "VM Provisioning");
1218
- spinner = createSpinner("Waiting for SSH...");
1219
- spinner.start();
1220
- const sshReady = await waitForSsh(config.sshPort);
1221
- if (!sshReady) {
1222
- fail(spinner, "SSH connection timed out");
1223
- process.exit(1);
1233
+ },
1234
+ // Phase 3 SSH Keys
1235
+ {
1236
+ name: "SSH Key Setup",
1237
+ run: async (ctx, spinner) => {
1238
+ const { config } = ctx;
1239
+ await withSpinner(spinner, "Generating SSH key...", async () => {
1240
+ await generateSshKey();
1241
+ addSshConfig(config.sshPort);
1242
+ });
1224
1243
  }
1225
- succeed(spinner, "SSH connected");
1226
- spinner = createSpinner("Uploading NEXUS release tarball...");
1227
- spinner.start();
1228
- await sshUploadFile(config.sshPort, tarballPath, "/tmp/nexus-release.tar.gz");
1229
- succeed(spinner, "Tarball uploaded");
1230
- spinner = createSpinner("Staging API keys...");
1231
- spinner.start();
1232
- const keysContent = Object.entries(keys).filter(([, v]) => v).map(([k, v]) => `${k}=${v}`).join("\n") + "\n";
1233
- const tmpKeysPath = path6.join(os2.tmpdir(), `.nexus-keys-${crypto4.randomBytes(8).toString("hex")}`);
1234
- fs6.writeFileSync(tmpKeysPath, keysContent, { mode: 384 });
1235
- try {
1236
- await sshUploadFile(config.sshPort, tmpKeysPath, "/tmp/.nexus-env-keys");
1237
- await sshExec(config.sshPort, "chmod 600 /tmp/.nexus-env-keys");
1238
- } finally {
1239
- try {
1240
- fs6.writeFileSync(tmpKeysPath, "0".repeat(keysContent.length));
1241
- fs6.unlinkSync(tmpKeysPath);
1242
- } catch {
1243
- }
1244
+ },
1245
+ // Phase 4 Ubuntu Image
1246
+ {
1247
+ name: "VM Image Download",
1248
+ run: async (ctx, spinner) => {
1249
+ const { platform } = ctx;
1250
+ const imagePath = await withSpinner(
1251
+ spinner,
1252
+ `Downloading Ubuntu 24.04 (${platform.ubuntuImage})...`,
1253
+ () => downloadImage(platform)
1254
+ );
1255
+ ctx.imagePath = imagePath;
1244
1256
  }
1245
- succeed(spinner, "API keys staged");
1246
- spinner = createSpinner("Cloud-init provisioning (extracting NEXUS, building Docker, installing deps)...");
1247
- spinner.start();
1248
- const cloudInitDone = await waitForCloudInit(config.sshPort);
1249
- if (!cloudInitDone) {
1250
- fail(spinner, "Cloud-init timed out");
1251
- log.warn("You can check progress with: buildwithnexus ssh then: tail -f /var/log/cloud-init-output.log");
1252
- process.exit(1);
1257
+ },
1258
+ // Phase 5 — Cloud-Init
1259
+ {
1260
+ name: "Cloud-Init Generation",
1261
+ run: async (ctx, spinner) => {
1262
+ const { keys, config } = ctx;
1263
+ const tarballPath = await withSpinner(spinner, "Locating release tarball...", async () => {
1264
+ return getReleaseTarball();
1265
+ });
1266
+ ctx.tarballPath = tarballPath;
1267
+ const isoPath = await withSpinner(spinner, "Rendering cloud-init...", async () => {
1268
+ const pubKey = getPubKey();
1269
+ const template = getCloudInitTemplate();
1270
+ const userDataPath = await renderCloudInit({ sshPubKey: pubKey, keys, config }, template);
1271
+ return createCloudInitIso(userDataPath);
1272
+ });
1273
+ ctx.isoPath = isoPath;
1253
1274
  }
1254
- succeed(spinner, "VM fully provisioned");
1255
- spinner = createSpinner("Delivering API keys...");
1256
- spinner.start();
1257
- await sshExec(config.sshPort, "mkdir -p /home/nexus/.nexus && mv /tmp/.nexus-env-keys /home/nexus/.nexus/.env.keys && chown -R nexus:nexus /home/nexus/.nexus && chmod 600 /home/nexus/.nexus/.env.keys");
1258
- succeed(spinner, "API keys delivered securely");
1259
- showPhase(8, TOTAL_PHASES, "NEXUS Server Startup");
1260
- spinner = createSpinner("Waiting for NEXUS server...");
1261
- spinner.start();
1262
- const serverReady = await waitForServer(config.sshPort);
1263
- if (!serverReady) {
1264
- fail(spinner, "Server failed to start");
1265
- log.warn("Check logs: buildwithnexus logs");
1266
- process.exit(1);
1275
+ },
1276
+ // Phase 6 VM Boot
1277
+ {
1278
+ name: "VM Launch",
1279
+ run: async (ctx, spinner) => {
1280
+ const { platform, imagePath, isoPath, config } = ctx;
1281
+ spinner.text = "Checking port availability...";
1282
+ spinner.start();
1283
+ spinner.stop();
1284
+ spinner.clear();
1285
+ const requestedPorts = { ssh: config.sshPort, http: config.httpPort, https: config.httpsPort };
1286
+ const resolvedPorts = await resolvePortConflicts(requestedPorts);
1287
+ const diskPath = await withSpinner(spinner, "Creating disk and launching VM...", async () => {
1288
+ const disk = await createDisk(imagePath, config.vmDisk);
1289
+ await launchVm(platform, disk, isoPath, config.vmRam, config.vmCpus, resolvedPorts);
1290
+ return disk;
1291
+ });
1292
+ config.sshPort = resolvedPorts.ssh;
1293
+ config.httpPort = resolvedPorts.http;
1294
+ config.httpsPort = resolvedPorts.https;
1295
+ saveConfig(config);
1296
+ const portNote = resolvedPorts.ssh !== 2222 || resolvedPorts.http !== 4200 || resolvedPorts.https !== 8443 ? ` (ports: SSH=${resolvedPorts.ssh}, HTTP=${resolvedPorts.http}, HTTPS=${resolvedPorts.https})` : "";
1297
+ succeed(spinner, `VM launched (daemonized)${portNote}`);
1298
+ ctx.diskPath = diskPath;
1299
+ ctx.resolvedPorts = resolvedPorts;
1300
+ ctx.vmLaunched = true;
1267
1301
  }
1268
- succeed(spinner, "NEXUS server healthy on port 4200");
1269
- let tunnelUrl;
1270
- if (config.enableTunnel) {
1271
- showPhase(9, TOTAL_PHASES, "Cloudflare Tunnel");
1272
- spinner = createSpinner("Installing cloudflared...");
1302
+ },
1303
+ // Phase 7 — VM Provisioning
1304
+ {
1305
+ name: "VM Provisioning",
1306
+ run: async (ctx, spinner) => {
1307
+ const { config, keys, tarballPath } = ctx;
1308
+ const pinPath = path6.join(process.env.HOME || "~", ".buildwithnexus", "ssh", "vm_host_key.pin");
1309
+ if (fs6.existsSync(pinPath)) fs6.unlinkSync(pinPath);
1310
+ spinner.text = "Waiting for SSH...";
1311
+ spinner.start();
1312
+ const sshReady = await waitForSsh(config.sshPort);
1313
+ if (!sshReady) {
1314
+ fail(spinner, "SSH connection timed out");
1315
+ throw new Error("SSH connection timed out");
1316
+ }
1317
+ succeed(spinner, "SSH connected");
1318
+ await withSpinner(
1319
+ spinner,
1320
+ "Uploading NEXUS release tarball...",
1321
+ () => sshUploadFile(config.sshPort, tarballPath, "/tmp/nexus-release.tar.gz")
1322
+ );
1323
+ await withSpinner(spinner, "Staging API keys...", async () => {
1324
+ const keysContent = Object.entries(keys).filter(([, v]) => v).map(([k, v]) => `${k}=${v}`).join("\n") + "\n";
1325
+ const tmpKeysPath = path6.join(os2.tmpdir(), `.nexus-keys-${crypto4.randomBytes(8).toString("hex")}`);
1326
+ fs6.writeFileSync(tmpKeysPath, keysContent, { mode: 384 });
1327
+ try {
1328
+ await sshUploadFile(config.sshPort, tmpKeysPath, "/tmp/.nexus-env-keys");
1329
+ await sshExec(config.sshPort, "chmod 600 /tmp/.nexus-env-keys");
1330
+ } finally {
1331
+ try {
1332
+ fs6.writeFileSync(tmpKeysPath, "0".repeat(keysContent.length));
1333
+ fs6.unlinkSync(tmpKeysPath);
1334
+ } catch {
1335
+ }
1336
+ }
1337
+ });
1338
+ spinner.text = "Cloud-init provisioning \u2014 this takes 10-20 min (extracting NEXUS, building Docker, installing deps)...";
1339
+ spinner.start();
1340
+ const cloudInitDone = await waitForCloudInit(config.sshPort);
1341
+ if (!cloudInitDone) {
1342
+ fail(spinner, "Cloud-init timed out after 30 minutes");
1343
+ log.warn("Check progress: buildwithnexus ssh \u2192 tail -f /var/log/cloud-init-output.log");
1344
+ throw new Error("Cloud-init timed out");
1345
+ }
1346
+ succeed(spinner, "VM fully provisioned");
1347
+ await withSpinner(
1348
+ spinner,
1349
+ "Delivering API keys...",
1350
+ () => sshExec(
1351
+ config.sshPort,
1352
+ "mkdir -p /home/nexus/.nexus && mv /tmp/.nexus-env-keys /home/nexus/.nexus/.env.keys && chown -R nexus:nexus /home/nexus/.nexus && chmod 600 /home/nexus/.nexus/.env.keys"
1353
+ )
1354
+ );
1355
+ }
1356
+ },
1357
+ // Phase 8 — Server Health
1358
+ {
1359
+ name: "NEXUS Server Startup",
1360
+ run: async (ctx, spinner) => {
1361
+ const { config } = ctx;
1362
+ spinner.text = "Waiting for NEXUS server...";
1273
1363
  spinner.start();
1274
- await installCloudflared(config.sshPort, platform.arch);
1364
+ const serverReady = await waitForServer(config.sshPort);
1365
+ if (!serverReady) {
1366
+ fail(spinner, "Server failed to start");
1367
+ log.warn("Check logs: buildwithnexus logs");
1368
+ throw new Error("NEXUS server failed to start");
1369
+ }
1370
+ succeed(spinner, "NEXUS server healthy on port 4200");
1371
+ }
1372
+ },
1373
+ // Phase 9 — Cloudflare Tunnel
1374
+ {
1375
+ name: "Cloudflare Tunnel",
1376
+ run: async (ctx, spinner) => {
1377
+ const { config, platform } = ctx;
1378
+ if (!config.enableTunnel) {
1379
+ log.dim("Skipped (not enabled)");
1380
+ return;
1381
+ }
1382
+ await withSpinner(
1383
+ spinner,
1384
+ "Installing cloudflared...",
1385
+ () => installCloudflared(config.sshPort, platform.arch)
1386
+ );
1275
1387
  spinner.text = "Starting tunnel...";
1388
+ spinner.start();
1276
1389
  const url = await startTunnel(config.sshPort);
1277
1390
  if (url) {
1278
- tunnelUrl = url;
1391
+ ctx.tunnelUrl = url;
1279
1392
  succeed(spinner, `Tunnel active: ${url}`);
1280
1393
  } else {
1281
1394
  fail(spinner, "Tunnel failed to start (server still accessible locally)");
1282
1395
  }
1283
- } else {
1284
- showPhase(9, TOTAL_PHASES, "Cloudflare Tunnel");
1285
- log.dim("Skipped (not enabled)");
1286
1396
  }
1287
- showPhase(10, TOTAL_PHASES, "Complete");
1288
- showCompletion({
1289
- remote: tunnelUrl,
1290
- ssh: "buildwithnexus ssh"
1291
- });
1397
+ },
1398
+ // Phase 10 — Complete
1399
+ {
1400
+ name: "Complete",
1401
+ run: async (ctx) => {
1402
+ showCompletion({ remote: ctx.tunnelUrl, ssh: "buildwithnexus ssh" });
1403
+ }
1404
+ }
1405
+ ];
1406
+ function hasQemuLabel(installed) {
1407
+ return installed ? "QEMU ready" : "QEMU installed";
1408
+ }
1409
+ var TOTAL_PHASES = phases.length;
1410
+ async function runInit() {
1411
+ const ctx = { vmLaunched: false, tunnelUrl: void 0 };
1412
+ const spinner = createSpinner("");
1413
+ for (let i = 0; i < phases.length; i++) {
1414
+ const phase = phases[i];
1415
+ showPhase(i + 1, TOTAL_PHASES, phase.name);
1416
+ if (phase.skip?.(ctx)) {
1417
+ log.dim("Skipped");
1418
+ continue;
1419
+ }
1420
+ try {
1421
+ await phase.run(ctx, spinner);
1422
+ } catch (err) {
1423
+ try {
1424
+ spinner.stop();
1425
+ } catch {
1426
+ }
1427
+ if (ctx.vmLaunched) {
1428
+ process.stderr.write(chalk6.dim("\n Stopping VM due to init failure...\n"));
1429
+ try {
1430
+ stopVm();
1431
+ } catch {
1432
+ }
1433
+ }
1434
+ throw err;
1435
+ }
1436
+ }
1437
+ }
1438
+ var initCommand = new Command("init").description("Scaffold and launch a new NEXUS runtime").action(async () => {
1439
+ try {
1440
+ await runInit();
1292
1441
  } catch (err) {
1293
1442
  const safeErr = redactError(err);
1294
1443
  log.error(`Init failed: ${safeErr.message}`);
@@ -1394,7 +1543,7 @@ var stopCommand = new Command3("stop").description("Gracefully shut down the NEX
1394
1543
 
1395
1544
  // src/commands/status.ts
1396
1545
  import { Command as Command4 } from "commander";
1397
- import chalk6 from "chalk";
1546
+ import chalk7 from "chalk";
1398
1547
  init_secrets();
1399
1548
  init_qemu();
1400
1549
  var statusCommand = new Command4("status").description("Check NEXUS runtime health").option("--json", "Output as JSON").action(async (opts) => {
@@ -1409,15 +1558,15 @@ var statusCommand = new Command4("status").description("Check NEXUS runtime heal
1409
1558
  console.log(JSON.stringify({ ...health, pid: getVmPid(), ports: { ssh: config.sshPort, http: config.httpPort, https: config.httpsPort } }, null, 2));
1410
1559
  return;
1411
1560
  }
1412
- const check = (ok) => ok ? chalk6.green("\u25CF") : chalk6.red("\u25CB");
1561
+ const check = (ok) => ok ? chalk7.green("\u25CF") : chalk7.red("\u25CB");
1413
1562
  console.log("");
1414
- console.log(chalk6.bold(" NEXUS Runtime Status"));
1563
+ console.log(chalk7.bold(" NEXUS Runtime Status"));
1415
1564
  console.log("");
1416
- console.log(` ${check(health.vmRunning)} VM ${health.vmRunning ? chalk6.green("running") + chalk6.dim(` (PID ${getVmPid()})`) : chalk6.red("stopped")}`);
1417
- console.log(` ${check(health.sshReady)} SSH ${health.sshReady ? chalk6.green("connected") + chalk6.dim(` (port ${config.sshPort})`) : chalk6.red("unreachable")}`);
1418
- console.log(` ${check(health.dockerReady)} Docker ${health.dockerReady ? chalk6.green("ready") : chalk6.red("not ready")}`);
1419
- console.log(` ${check(health.serverHealthy)} Server ${health.serverHealthy ? chalk6.green("healthy") + chalk6.dim(` (port ${config.httpPort})`) : chalk6.red("unhealthy")}`);
1420
- console.log(` ${check(!!health.tunnelUrl)} Tunnel ${health.tunnelUrl ? chalk6.green(health.tunnelUrl) : chalk6.dim("not active")}`);
1565
+ console.log(` ${check(health.vmRunning)} VM ${health.vmRunning ? chalk7.green("running") + chalk7.dim(` (PID ${getVmPid()})`) : chalk7.red("stopped")}`);
1566
+ console.log(` ${check(health.sshReady)} SSH ${health.sshReady ? chalk7.green("connected") + chalk7.dim(` (port ${config.sshPort})`) : chalk7.red("unreachable")}`);
1567
+ console.log(` ${check(health.dockerReady)} Docker ${health.dockerReady ? chalk7.green("ready") : chalk7.red("not ready")}`);
1568
+ console.log(` ${check(health.serverHealthy)} Server ${health.serverHealthy ? chalk7.green("healthy") + chalk7.dim(` (port ${config.httpPort})`) : chalk7.red("unhealthy")}`);
1569
+ console.log(` ${check(!!health.tunnelUrl)} Tunnel ${health.tunnelUrl ? chalk7.green(health.tunnelUrl) : chalk7.dim("not active")}`);
1421
1570
  console.log("");
1422
1571
  if (health.serverHealthy) {
1423
1572
  log.success(`NEXUS CLI ready \u2014 connect via: buildwithnexus ssh`);
@@ -1426,7 +1575,7 @@ var statusCommand = new Command4("status").description("Check NEXUS runtime heal
1426
1575
 
1427
1576
  // src/commands/doctor.ts
1428
1577
  import { Command as Command5 } from "commander";
1429
- import chalk7 from "chalk";
1578
+ import chalk8 from "chalk";
1430
1579
  import fs7 from "fs";
1431
1580
  init_qemu();
1432
1581
  init_secrets();
@@ -1434,12 +1583,12 @@ import path8 from "path";
1434
1583
  import { execa as execa4 } from "execa";
1435
1584
  var doctorCommand = new Command5("doctor").description("Diagnose NEXUS runtime environment").action(async () => {
1436
1585
  const platform = detectPlatform();
1437
- const check = (ok) => ok ? chalk7.green("\u2713") : chalk7.red("\u2717");
1586
+ const check = (ok) => ok ? chalk8.green("\u2713") : chalk8.red("\u2717");
1438
1587
  console.log("");
1439
- console.log(chalk7.bold(" NEXUS Doctor"));
1588
+ console.log(chalk8.bold(" NEXUS Doctor"));
1440
1589
  console.log("");
1441
1590
  const nodeOk = Number(process.versions.node.split(".")[0]) >= 18;
1442
- console.log(` ${check(nodeOk)} Node.js ${process.versions.node} ${nodeOk ? "" : chalk7.red("(need >= 18)")}`);
1591
+ console.log(` ${check(nodeOk)} Node.js ${process.versions.node} ${nodeOk ? "" : chalk8.red("(need >= 18)")}`);
1443
1592
  console.log(` ${check(true)} Platform: ${platform.os} ${platform.arch}`);
1444
1593
  const qemuOk = await isQemuInstalled(platform);
1445
1594
  if (qemuOk) {
@@ -1479,14 +1628,14 @@ var doctorCommand = new Command5("doctor").description("Diagnose NEXUS runtime e
1479
1628
  });
1480
1629
  server.listen(port);
1481
1630
  });
1482
- console.log(` ${check(available)} Port ${port} (${name}) ${available ? "available" : chalk7.red("in use")}`);
1631
+ console.log(` ${check(available)} Port ${port} (${name}) ${available ? "available" : chalk8.red("in use")}`);
1483
1632
  } catch {
1484
1633
  console.log(` ${check(false)} Port ${port} (${name}) \u2014 check failed`);
1485
1634
  }
1486
1635
  }
1487
1636
  }
1488
1637
  const biosOk = fs7.existsSync(platform.biosPath);
1489
- console.log(` ${check(biosOk)} UEFI firmware ${biosOk ? "" : chalk7.dim(platform.biosPath)}`);
1638
+ console.log(` ${check(biosOk)} UEFI firmware ${biosOk ? "" : chalk8.dim(platform.biosPath)}`);
1490
1639
  console.log("");
1491
1640
  if (qemuOk && isoTool && biosOk) {
1492
1641
  log.success("Environment ready for NEXUS");
@@ -1597,7 +1746,7 @@ var updateCommand = new Command7("update").description("Update NEXUS to the late
1597
1746
 
1598
1747
  // src/commands/destroy.ts
1599
1748
  import { Command as Command8 } from "commander";
1600
- import chalk8 from "chalk";
1749
+ import chalk9 from "chalk";
1601
1750
  import fs9 from "fs";
1602
1751
  import { input as input2 } from "@inquirer/prompts";
1603
1752
  init_secrets();
@@ -1607,11 +1756,11 @@ var destroyCommand = new Command8("destroy").description("Remove NEXUS VM and al
1607
1756
  const config = loadConfig();
1608
1757
  if (!opts.force) {
1609
1758
  console.log("");
1610
- console.log(chalk8.red.bold(" This will permanently delete:"));
1611
- console.log(chalk8.red(" - NEXUS VM and all data inside it"));
1612
- console.log(chalk8.red(" - VM disk images"));
1613
- console.log(chalk8.red(" - SSH keys"));
1614
- console.log(chalk8.red(" - Configuration and API keys"));
1759
+ console.log(chalk9.red.bold(" This will permanently delete:"));
1760
+ console.log(chalk9.red(" - NEXUS VM and all data inside it"));
1761
+ console.log(chalk9.red(" - VM disk images"));
1762
+ console.log(chalk9.red(" - SSH keys"));
1763
+ console.log(chalk9.red(" - Configuration and API keys"));
1615
1764
  console.log("");
1616
1765
  const confirm2 = await input2({
1617
1766
  message: 'Type "destroy" to confirm:'
@@ -1655,7 +1804,7 @@ var destroyCommand = new Command8("destroy").description("Remove NEXUS VM and al
1655
1804
  // src/commands/keys.ts
1656
1805
  import { Command as Command9 } from "commander";
1657
1806
  import { password as password2 } from "@inquirer/prompts";
1658
- import chalk9 from "chalk";
1807
+ import chalk10 from "chalk";
1659
1808
  init_secrets();
1660
1809
  init_dlp();
1661
1810
  var keysCommand = new Command9("keys").description("Manage API keys");
@@ -1665,10 +1814,10 @@ keysCommand.command("list").description("Show configured API keys (masked)").act
1665
1814
  log.error("No keys configured. Run: buildwithnexus init");
1666
1815
  process.exit(1);
1667
1816
  }
1668
- console.log(chalk9.bold("\n Configured Keys\n"));
1817
+ console.log(chalk10.bold("\n Configured Keys\n"));
1669
1818
  for (const [name, value] of Object.entries(keys)) {
1670
1819
  if (value) {
1671
- console.log(` ${chalk9.cyan(name.padEnd(24))} ${maskKey(value)}`);
1820
+ console.log(` ${chalk10.cyan(name.padEnd(24))} ${maskKey(value)}`);
1672
1821
  }
1673
1822
  }
1674
1823
  console.log("");
@@ -1733,18 +1882,18 @@ var sshCommand = new Command10("ssh").description("Open an SSH session into the
1733
1882
 
1734
1883
  // src/commands/brainstorm.ts
1735
1884
  import { Command as Command11 } from "commander";
1736
- import chalk10 from "chalk";
1885
+ import chalk11 from "chalk";
1737
1886
  import { input as input3 } from "@inquirer/prompts";
1738
1887
  init_secrets();
1739
1888
  init_qemu();
1740
1889
  init_ssh();
1741
1890
  init_dlp();
1742
- var COS_PREFIX = chalk10.bold.cyan(" Chief of Staff");
1743
- var YOU_PREFIX = chalk10.bold.white(" You");
1744
- var DIVIDER = chalk10.dim(" " + "\u2500".repeat(56));
1891
+ var COS_PREFIX = chalk11.bold.cyan(" Chief of Staff");
1892
+ var YOU_PREFIX = chalk11.bold.white(" You");
1893
+ var DIVIDER = chalk11.dim(" " + "\u2500".repeat(56));
1745
1894
  function formatResponse(text) {
1746
1895
  const lines = text.split("\n");
1747
- return lines.map((line) => chalk10.white(" " + line)).join("\n");
1896
+ return lines.map((line) => chalk11.white(" " + line)).join("\n");
1748
1897
  }
1749
1898
  async function sendMessage(sshPort, message, source) {
1750
1899
  const payload = JSON.stringify({ message, source });
@@ -1787,13 +1936,13 @@ var brainstormCommand = new Command11("brainstorm").description("Brainstorm an i
1787
1936
  }
1788
1937
  succeed(spinner, "Connected to NEXUS");
1789
1938
  console.log("");
1790
- 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"));
1791
- console.log(chalk10.bold(" \u2551 ") + chalk10.bold.cyan("NEXUS Brainstorm Session") + chalk10.bold(" \u2551"));
1792
- 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"));
1793
- console.log(chalk10.bold(" \u2551 ") + chalk10.dim("The Chief of Staff will discuss your idea with the".padEnd(55)) + chalk10.bold("\u2551"));
1794
- console.log(chalk10.bold(" \u2551 ") + chalk10.dim("NEXUS team and share their recommendations.".padEnd(55)) + chalk10.bold("\u2551"));
1795
- console.log(chalk10.bold(" \u2551 ") + chalk10.dim("Type 'exit' or 'quit' to end the session.".padEnd(55)) + chalk10.bold("\u2551"));
1796
- 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"));
1939
+ console.log(chalk11.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"));
1940
+ console.log(chalk11.bold(" \u2551 ") + chalk11.bold.cyan("NEXUS Brainstorm Session") + chalk11.bold(" \u2551"));
1941
+ console.log(chalk11.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"));
1942
+ console.log(chalk11.bold(" \u2551 ") + chalk11.dim("The Chief of Staff will discuss your idea with the".padEnd(55)) + chalk11.bold("\u2551"));
1943
+ console.log(chalk11.bold(" \u2551 ") + chalk11.dim("NEXUS team and share their recommendations.".padEnd(55)) + chalk11.bold("\u2551"));
1944
+ console.log(chalk11.bold(" \u2551 ") + chalk11.dim("Type 'exit' or 'quit' to end the session.".padEnd(55)) + chalk11.bold("\u2551"));
1945
+ console.log(chalk11.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"));
1797
1946
  console.log("");
1798
1947
  let idea = ideaWords.length > 0 ? ideaWords.join(" ") : "";
1799
1948
  if (!idea) {
@@ -1810,7 +1959,7 @@ var brainstormCommand = new Command11("brainstorm").description("Brainstorm an i
1810
1959
  while (true) {
1811
1960
  turn++;
1812
1961
  if (turn === 1) {
1813
- console.log(`${YOU_PREFIX}: ${chalk10.white(idea)}`);
1962
+ console.log(`${YOU_PREFIX}: ${chalk11.white(idea)}`);
1814
1963
  }
1815
1964
  console.log(DIVIDER);
1816
1965
  const thinking = createSpinner(
@@ -1828,17 +1977,17 @@ var brainstormCommand = new Command11("brainstorm").description("Brainstorm an i
1828
1977
  console.log(formatResponse(redact(response)));
1829
1978
  console.log(DIVIDER);
1830
1979
  const followUp = await input3({
1831
- message: chalk10.bold("You:")
1980
+ message: chalk11.bold("You:")
1832
1981
  });
1833
1982
  const trimmed = followUp.trim().toLowerCase();
1834
1983
  if (!trimmed || trimmed === "exit" || trimmed === "quit" || trimmed === "q") {
1835
1984
  console.log("");
1836
1985
  log.success("Brainstorm session ended");
1837
- console.log(chalk10.dim(" Run again anytime: buildwithnexus brainstorm"));
1986
+ console.log(chalk11.dim(" Run again anytime: buildwithnexus brainstorm"));
1838
1987
  console.log("");
1839
1988
  return;
1840
1989
  }
1841
- console.log(`${YOU_PREFIX}: ${chalk10.white(followUp)}`);
1990
+ console.log(`${YOU_PREFIX}: ${chalk11.white(followUp)}`);
1842
1991
  currentMessage = `[BRAINSTORM FOLLOW-UP] The CEO responds: ${followUp}`;
1843
1992
  }
1844
1993
  } catch (err) {
@@ -1855,18 +2004,18 @@ var brainstormCommand = new Command11("brainstorm").description("Brainstorm an i
1855
2004
 
1856
2005
  // src/commands/ninety-nine.ts
1857
2006
  import { Command as Command12 } from "commander";
1858
- import chalk11 from "chalk";
2007
+ import chalk12 from "chalk";
1859
2008
  import { input as input4 } from "@inquirer/prompts";
1860
2009
  init_secrets();
1861
2010
  init_qemu();
1862
2011
  init_ssh();
1863
2012
  init_dlp();
1864
- var AGENT_PREFIX = chalk11.bold.green(" 99 \u276F");
1865
- var YOU_PREFIX2 = chalk11.bold.white(" You");
1866
- var DIVIDER2 = chalk11.dim(" " + "\u2500".repeat(56));
2013
+ var AGENT_PREFIX = chalk12.bold.green(" 99 \u276F");
2014
+ var YOU_PREFIX2 = chalk12.bold.white(" You");
2015
+ var DIVIDER2 = chalk12.dim(" " + "\u2500".repeat(56));
1867
2016
  function formatAgentActivity(text) {
1868
2017
  const lines = text.split("\n");
1869
- return lines.map((line) => chalk11.white(" " + line)).join("\n");
2018
+ return lines.map((line) => chalk12.white(" " + line)).join("\n");
1870
2019
  }
1871
2020
  function parsePrefixes(instruction) {
1872
2021
  const files = [];
@@ -1930,14 +2079,14 @@ var ninetyNineCommand = new Command12("99").description("AI pair-programming ses
1930
2079
  }
1931
2080
  succeed(spinner, "Connected to NEXUS");
1932
2081
  console.log("");
1933
- console.log(chalk11.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"));
1934
- console.log(chalk11.bold(" \u2551 ") + chalk11.bold.green("/99 Pair Programming") + chalk11.dim(" \u2014 powered by NEXUS") + chalk11.bold(" \u2551"));
1935
- console.log(chalk11.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"));
1936
- console.log(chalk11.bold(" \u2551 ") + chalk11.dim("Describe what you want changed. NEXUS engineers".padEnd(55)) + chalk11.bold("\u2551"));
1937
- console.log(chalk11.bold(" \u2551 ") + chalk11.dim("analyze and modify your code in real time.".padEnd(55)) + chalk11.bold("\u2551"));
1938
- console.log(chalk11.bold(" \u2551 ") + chalk11.dim("Use @file to attach context, #rule to load rules.".padEnd(55)) + chalk11.bold("\u2551"));
1939
- console.log(chalk11.bold(" \u2551 ") + chalk11.dim("Type 'exit' or 'quit' to end the session.".padEnd(55)) + chalk11.bold("\u2551"));
1940
- console.log(chalk11.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"));
2082
+ console.log(chalk12.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"));
2083
+ console.log(chalk12.bold(" \u2551 ") + chalk12.bold.green("/99 Pair Programming") + chalk12.dim(" \u2014 powered by NEXUS") + chalk12.bold(" \u2551"));
2084
+ console.log(chalk12.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"));
2085
+ console.log(chalk12.bold(" \u2551 ") + chalk12.dim("Describe what you want changed. NEXUS engineers".padEnd(55)) + chalk12.bold("\u2551"));
2086
+ console.log(chalk12.bold(" \u2551 ") + chalk12.dim("analyze and modify your code in real time.".padEnd(55)) + chalk12.bold("\u2551"));
2087
+ console.log(chalk12.bold(" \u2551 ") + chalk12.dim("Use @file to attach context, #rule to load rules.".padEnd(55)) + chalk12.bold("\u2551"));
2088
+ console.log(chalk12.bold(" \u2551 ") + chalk12.dim("Type 'exit' or 'quit' to end the session.".padEnd(55)) + chalk12.bold("\u2551"));
2089
+ console.log(chalk12.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"));
1941
2090
  console.log("");
1942
2091
  const cwd = process.cwd();
1943
2092
  if (opts.edit) {
@@ -1946,7 +2095,7 @@ var ninetyNineCommand = new Command12("99").description("AI pair-programming ses
1946
2095
  });
1947
2096
  const { cleaned, files, rules } = parsePrefixes(instruction);
1948
2097
  const fullInstruction = `Edit file ${opts.edit}: ${cleaned}`;
1949
- console.log(`${YOU_PREFIX2}: ${chalk11.white(fullInstruction)}`);
2098
+ console.log(`${YOU_PREFIX2}: ${chalk12.white(fullInstruction)}`);
1950
2099
  console.log(DIVIDER2);
1951
2100
  const thinking = createSpinner("NEXUS engineers analyzing the file...");
1952
2101
  thinking.start();
@@ -1960,7 +2109,7 @@ var ninetyNineCommand = new Command12("99").description("AI pair-programming ses
1960
2109
  }
1961
2110
  if (opts.search) {
1962
2111
  const fullInstruction = `Search the codebase for: ${opts.search}`;
1963
- console.log(`${YOU_PREFIX2}: ${chalk11.white(fullInstruction)}`);
2112
+ console.log(`${YOU_PREFIX2}: ${chalk12.white(fullInstruction)}`);
1964
2113
  console.log(DIVIDER2);
1965
2114
  const thinking = createSpinner("Searching with NEXUS context...");
1966
2115
  thinking.start();
@@ -1974,7 +2123,7 @@ var ninetyNineCommand = new Command12("99").description("AI pair-programming ses
1974
2123
  }
1975
2124
  if (opts.debug) {
1976
2125
  const fullInstruction = "Debug the current issue \u2014 analyze recent errors, identify the root cause, and propose a fix";
1977
- console.log(`${YOU_PREFIX2}: ${chalk11.white(fullInstruction)}`);
2126
+ console.log(`${YOU_PREFIX2}: ${chalk12.white(fullInstruction)}`);
1978
2127
  console.log(DIVIDER2);
1979
2128
  const thinking = createSpinner("NEXUS debugger agent analyzing...");
1980
2129
  thinking.start();
@@ -1989,7 +2138,7 @@ var ninetyNineCommand = new Command12("99").description("AI pair-programming ses
1989
2138
  let initialInstruction = instructionWords.length > 0 ? instructionWords.join(" ") : "";
1990
2139
  if (!initialInstruction) {
1991
2140
  initialInstruction = await input4({
1992
- message: chalk11.green("99 \u276F")
2141
+ message: chalk12.green("99 \u276F")
1993
2142
  });
1994
2143
  if (!initialInstruction.trim()) {
1995
2144
  log.warn("No instruction provided");
@@ -2004,13 +2153,13 @@ var ninetyNineCommand = new Command12("99").description("AI pair-programming ses
2004
2153
  const display = currentInstruction;
2005
2154
  const nexusInstruction = cleaned || currentInstruction;
2006
2155
  if (turn === 1) {
2007
- console.log(`${YOU_PREFIX2}: ${chalk11.white(display)}`);
2156
+ console.log(`${YOU_PREFIX2}: ${chalk12.white(display)}`);
2008
2157
  }
2009
2158
  if (files.length > 0) {
2010
- console.log(chalk11.dim(` Attaching: ${files.join(", ")}`));
2159
+ console.log(chalk12.dim(` Attaching: ${files.join(", ")}`));
2011
2160
  }
2012
2161
  if (rules.length > 0) {
2013
- console.log(chalk11.dim(` Rules: ${rules.join(", ")}`));
2162
+ console.log(chalk12.dim(` Rules: ${rules.join(", ")}`));
2014
2163
  }
2015
2164
  console.log(DIVIDER2);
2016
2165
  const thinking = createSpinner(
@@ -2024,17 +2173,17 @@ var ninetyNineCommand = new Command12("99").description("AI pair-programming ses
2024
2173
  console.log(formatAgentActivity(redact(response)));
2025
2174
  console.log(DIVIDER2);
2026
2175
  const followUp = await input4({
2027
- message: chalk11.green("99 \u276F")
2176
+ message: chalk12.green("99 \u276F")
2028
2177
  });
2029
2178
  const trimmed = followUp.trim().toLowerCase();
2030
2179
  if (!trimmed || trimmed === "exit" || trimmed === "quit" || trimmed === "q") {
2031
2180
  console.log("");
2032
2181
  log.success("/99 session ended");
2033
- console.log(chalk11.dim(" Run again: buildwithnexus 99"));
2182
+ console.log(chalk12.dim(" Run again: buildwithnexus 99"));
2034
2183
  console.log("");
2035
2184
  return;
2036
2185
  }
2037
- console.log(`${YOU_PREFIX2}: ${chalk11.white(followUp)}`);
2186
+ console.log(`${YOU_PREFIX2}: ${chalk12.white(followUp)}`);
2038
2187
  currentInstruction = followUp;
2039
2188
  }
2040
2189
  } catch (err) {
@@ -2051,7 +2200,7 @@ var ninetyNineCommand = new Command12("99").description("AI pair-programming ses
2051
2200
 
2052
2201
  // src/commands/shell.ts
2053
2202
  import { Command as Command13 } from "commander";
2054
- import chalk14 from "chalk";
2203
+ import chalk15 from "chalk";
2055
2204
  init_secrets();
2056
2205
  init_qemu();
2057
2206
  init_ssh();
@@ -2062,7 +2211,7 @@ init_secrets();
2062
2211
  import readline from "readline";
2063
2212
  import fs10 from "fs";
2064
2213
  import path11 from "path";
2065
- import chalk12 from "chalk";
2214
+ import chalk13 from "chalk";
2066
2215
  var HISTORY_FILE = path11.join(NEXUS_HOME2, "shell_history");
2067
2216
  var MAX_HISTORY = 1e3;
2068
2217
  var Repl = class {
@@ -2097,7 +2246,7 @@ var Repl = class {
2097
2246
  this.rl = readline.createInterface({
2098
2247
  input: process.stdin,
2099
2248
  output: process.stdout,
2100
- prompt: chalk12.bold.cyan("nexus") + chalk12.dim(" \u276F "),
2249
+ prompt: chalk13.bold.cyan("nexus") + chalk13.dim(" \u276F "),
2101
2250
  history: this.history,
2102
2251
  historySize: MAX_HISTORY,
2103
2252
  terminal: true
@@ -2127,25 +2276,25 @@ var Repl = class {
2127
2276
  try {
2128
2277
  await cmd.handler();
2129
2278
  } catch (err) {
2130
- console.log(chalk12.red(` \u2717 Command failed: ${err.message}`));
2279
+ console.log(chalk13.red(` \u2717 Command failed: ${err.message}`));
2131
2280
  }
2132
2281
  this.rl?.prompt();
2133
2282
  return;
2134
2283
  }
2135
- console.log(chalk12.yellow(` Unknown command: /${cmdName}. Type /help for available commands.`));
2284
+ console.log(chalk13.yellow(` Unknown command: /${cmdName}. Type /help for available commands.`));
2136
2285
  this.rl?.prompt();
2137
2286
  return;
2138
2287
  }
2139
2288
  try {
2140
2289
  await this.onMessage(trimmed);
2141
2290
  } catch (err) {
2142
- console.log(chalk12.red(` \u2717 ${err.message}`));
2291
+ console.log(chalk13.red(` \u2717 ${err.message}`));
2143
2292
  }
2144
2293
  this.rl?.prompt();
2145
2294
  });
2146
2295
  this.rl.on("close", () => {
2147
2296
  this.saveHistory();
2148
- console.log(chalk12.dim("\n Session ended."));
2297
+ console.log(chalk13.dim("\n Session ended."));
2149
2298
  process.exit(0);
2150
2299
  });
2151
2300
  this.rl.on("SIGINT", () => {
@@ -2154,15 +2303,15 @@ var Repl = class {
2154
2303
  }
2155
2304
  showHelp() {
2156
2305
  console.log("");
2157
- console.log(chalk12.bold(" Available Commands:"));
2158
- console.log(chalk12.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2306
+ console.log(chalk13.bold(" Available Commands:"));
2307
+ console.log(chalk13.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2159
2308
  for (const [name, cmd] of this.commands) {
2160
- console.log(` ${chalk12.cyan("/" + name.padEnd(14))} ${chalk12.dim(cmd.description)}`);
2309
+ console.log(` ${chalk13.cyan("/" + name.padEnd(14))} ${chalk13.dim(cmd.description)}`);
2161
2310
  }
2162
- console.log(` ${chalk12.cyan("/help".padEnd(15))} ${chalk12.dim("Show this help message")}`);
2163
- console.log(` ${chalk12.cyan("/exit".padEnd(15))} ${chalk12.dim("Exit the shell")}`);
2164
- console.log(chalk12.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2165
- console.log(chalk12.dim(" Type anything else to chat with NEXUS"));
2311
+ console.log(` ${chalk13.cyan("/help".padEnd(15))} ${chalk13.dim("Show this help message")}`);
2312
+ console.log(` ${chalk13.cyan("/exit".padEnd(15))} ${chalk13.dim("Exit the shell")}`);
2313
+ console.log(chalk13.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2314
+ console.log(chalk13.dim(" Type anything else to chat with NEXUS"));
2166
2315
  console.log("");
2167
2316
  }
2168
2317
  write(text) {
@@ -2188,17 +2337,17 @@ var Repl = class {
2188
2337
  init_ssh();
2189
2338
  init_secrets();
2190
2339
  init_dlp();
2191
- import chalk13 from "chalk";
2340
+ import chalk14 from "chalk";
2192
2341
  var ROLE_COLORS = {
2193
- "Chief of Staff": chalk13.bold.cyan,
2194
- "VP Engineering": chalk13.bold.blue,
2195
- "VP Product": chalk13.bold.magenta,
2196
- "Senior Engineer": chalk13.bold.green,
2197
- "Engineer": chalk13.green,
2198
- "QA Lead": chalk13.bold.yellow,
2199
- "Security Engineer": chalk13.bold.red,
2200
- "DevOps Engineer": chalk13.bold.hex("#FF8C00"),
2201
- "default": chalk13.bold.white
2342
+ "Chief of Staff": chalk14.bold.cyan,
2343
+ "VP Engineering": chalk14.bold.blue,
2344
+ "VP Product": chalk14.bold.magenta,
2345
+ "Senior Engineer": chalk14.bold.green,
2346
+ "Engineer": chalk14.green,
2347
+ "QA Lead": chalk14.bold.yellow,
2348
+ "Security Engineer": chalk14.bold.red,
2349
+ "DevOps Engineer": chalk14.bold.hex("#FF8C00"),
2350
+ "default": chalk14.bold.white
2202
2351
  };
2203
2352
  function getColor(role) {
2204
2353
  if (!role) return ROLE_COLORS["default"];
@@ -2209,15 +2358,15 @@ function formatEvent(event) {
2209
2358
  const prefix = event.role ? color(` [${event.role}]`) : "";
2210
2359
  switch (event.type) {
2211
2360
  case "agent_thinking":
2212
- return `${prefix} ${chalk13.dim("thinking...")}`;
2361
+ return `${prefix} ${chalk14.dim("thinking...")}`;
2213
2362
  case "agent_response":
2214
2363
  return `${prefix} ${redact(event.content ?? "")}`;
2215
2364
  case "task_delegated":
2216
- return `${prefix} ${chalk13.dim("\u2192")} delegated to ${chalk13.bold(event.target ?? "agent")}`;
2365
+ return `${prefix} ${chalk14.dim("\u2192")} delegated to ${chalk14.bold(event.target ?? "agent")}`;
2217
2366
  case "agent_complete":
2218
- return `${prefix} ${chalk13.green("\u2713")} ${chalk13.dim("complete")}`;
2367
+ return `${prefix} ${chalk14.green("\u2713")} ${chalk14.dim("complete")}`;
2219
2368
  case "error":
2220
- return ` ${chalk13.red("\u2717")} ${redact(event.content ?? "Unknown error")}`;
2369
+ return ` ${chalk14.red("\u2717")} ${redact(event.content ?? "Unknown error")}`;
2221
2370
  case "heartbeat":
2222
2371
  return null;
2223
2372
  default:
@@ -2300,19 +2449,19 @@ async function sendMessage2(sshPort, message) {
2300
2449
  }
2301
2450
  }
2302
2451
  function showShellBanner(health) {
2303
- const check = chalk14.green("\u2713");
2304
- const cross = chalk14.red("\u2717");
2452
+ const check = chalk15.green("\u2713");
2453
+ const cross = chalk15.red("\u2717");
2305
2454
  console.log("");
2306
- console.log(chalk14.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"));
2307
- console.log(chalk14.bold(" \u2551 ") + chalk14.bold.cyan("NEXUS Interactive Shell") + chalk14.bold(" \u2551"));
2308
- console.log(chalk14.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"));
2309
- console.log(chalk14.bold(" \u2551 ") + `${health.vmRunning ? check : cross} VM ${health.sshReady ? check : cross} SSH ${health.dockerReady ? check : cross} Docker ${health.serverHealthy ? check : cross} Engine`.padEnd(55) + chalk14.bold("\u2551"));
2455
+ console.log(chalk15.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"));
2456
+ console.log(chalk15.bold(" \u2551 ") + chalk15.bold.cyan("NEXUS Interactive Shell") + chalk15.bold(" \u2551"));
2457
+ console.log(chalk15.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"));
2458
+ console.log(chalk15.bold(" \u2551 ") + `${health.vmRunning ? check : cross} VM ${health.sshReady ? check : cross} SSH ${health.dockerReady ? check : cross} Docker ${health.serverHealthy ? check : cross} Engine`.padEnd(55) + chalk15.bold("\u2551"));
2310
2459
  if (health.tunnelUrl) {
2311
- console.log(chalk14.bold(" \u2551 ") + chalk14.dim(`Tunnel: ${health.tunnelUrl}`.padEnd(55)) + chalk14.bold("\u2551"));
2460
+ console.log(chalk15.bold(" \u2551 ") + chalk15.dim(`Tunnel: ${health.tunnelUrl}`.padEnd(55)) + chalk15.bold("\u2551"));
2312
2461
  }
2313
- console.log(chalk14.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"));
2314
- console.log(chalk14.bold(" \u2551 ") + chalk14.dim("Type naturally to chat \xB7 /help for commands".padEnd(55)) + chalk14.bold("\u2551"));
2315
- console.log(chalk14.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"));
2462
+ console.log(chalk15.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"));
2463
+ console.log(chalk15.bold(" \u2551 ") + chalk15.dim("Type naturally to chat \xB7 /help for commands".padEnd(55)) + chalk15.bold("\u2551"));
2464
+ console.log(chalk15.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"));
2316
2465
  console.log("");
2317
2466
  }
2318
2467
  async function getAgentList(sshPort) {
@@ -2322,13 +2471,13 @@ async function getAgentList(sshPort) {
2322
2471
  const agents = JSON.parse(stdout);
2323
2472
  if (!Array.isArray(agents)) return stdout;
2324
2473
  const lines = [""];
2325
- lines.push(chalk14.bold(" Registered Agents:"));
2326
- lines.push(chalk14.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2474
+ lines.push(chalk15.bold(" Registered Agents:"));
2475
+ lines.push(chalk15.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2327
2476
  for (const agent of agents) {
2328
2477
  const name = agent.name ?? agent.id ?? "unknown";
2329
2478
  const role = agent.role ?? "";
2330
- const status = agent.status === "active" ? chalk14.green("\u25CF") : chalk14.dim("\u25CB");
2331
- lines.push(` ${status} ${chalk14.bold(name.padEnd(24))} ${chalk14.dim(role)}`);
2479
+ const status = agent.status === "active" ? chalk15.green("\u25CF") : chalk15.dim("\u25CB");
2480
+ lines.push(` ${status} ${chalk15.bold(name.padEnd(24))} ${chalk15.dim(role)}`);
2332
2481
  }
2333
2482
  lines.push("");
2334
2483
  return lines.join("\n");
@@ -2340,11 +2489,11 @@ async function getStatus(sshPort) {
2340
2489
  try {
2341
2490
  const vmRunning = isVmRunning();
2342
2491
  const health = await checkHealth(sshPort, vmRunning);
2343
- const check = chalk14.green("\u2713");
2344
- const cross = chalk14.red("\u2717");
2492
+ const check = chalk15.green("\u2713");
2493
+ const cross = chalk15.red("\u2717");
2345
2494
  const lines = [""];
2346
- lines.push(chalk14.bold(" System Status:"));
2347
- lines.push(chalk14.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2495
+ lines.push(chalk15.bold(" System Status:"));
2496
+ lines.push(chalk15.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2348
2497
  lines.push(` ${health.vmRunning ? check : cross} Virtual Machine`);
2349
2498
  lines.push(` ${health.sshReady ? check : cross} SSH Connection`);
2350
2499
  lines.push(` ${health.dockerReady ? check : cross} Docker Engine`);
@@ -2366,17 +2515,17 @@ async function getCost(sshPort) {
2366
2515
  if (code !== 0) return " Could not retrieve cost data";
2367
2516
  const data = JSON.parse(stdout);
2368
2517
  const lines = [""];
2369
- lines.push(chalk14.bold(" Token Costs:"));
2370
- lines.push(chalk14.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2518
+ lines.push(chalk15.bold(" Token Costs:"));
2519
+ lines.push(chalk15.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2371
2520
  if (data.total !== void 0) {
2372
- lines.push(` Total: ${chalk14.bold.green("$" + Number(data.total).toFixed(4))}`);
2521
+ lines.push(` Total: ${chalk15.bold.green("$" + Number(data.total).toFixed(4))}`);
2373
2522
  }
2374
2523
  if (data.today !== void 0) {
2375
- lines.push(` Today: ${chalk14.bold("$" + Number(data.today).toFixed(4))}`);
2524
+ lines.push(` Today: ${chalk15.bold("$" + Number(data.today).toFixed(4))}`);
2376
2525
  }
2377
2526
  if (data.by_agent && typeof data.by_agent === "object") {
2378
2527
  lines.push("");
2379
- lines.push(chalk14.dim(" By Agent:"));
2528
+ lines.push(chalk15.dim(" By Agent:"));
2380
2529
  for (const [agent, cost] of Object.entries(data.by_agent)) {
2381
2530
  lines.push(` ${agent.padEnd(20)} $${Number(cost).toFixed(4)}`);
2382
2531
  }
@@ -2421,10 +2570,10 @@ var shellCommand2 = new Command13("shell").description("Launch the interactive N
2421
2570
  thinkingSpinner.stop();
2422
2571
  thinkingSpinner.clear();
2423
2572
  console.log("");
2424
- console.log(chalk14.bold.cyan(" Chief of Staff:"));
2573
+ console.log(chalk15.bold.cyan(" Chief of Staff:"));
2425
2574
  const lines = redact(response).split("\n");
2426
2575
  for (const line of lines) {
2427
- console.log(chalk14.white(" " + line));
2576
+ console.log(chalk15.white(" " + line));
2428
2577
  }
2429
2578
  console.log("");
2430
2579
  } catch (err) {
@@ -2438,14 +2587,14 @@ var shellCommand2 = new Command13("shell").description("Launch the interactive N
2438
2587
  description: "Brainstorm with the full NEXUS org (led by Chief of Staff)",
2439
2588
  handler: async () => {
2440
2589
  console.log("");
2441
- console.log(chalk14.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"));
2442
- console.log(chalk14.bold(" \u2551 ") + chalk14.bold.cyan("NEXUS Brainstorm Session") + chalk14.bold(" \u2551"));
2443
- console.log(chalk14.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"));
2444
- console.log(chalk14.bold(" \u2551 ") + chalk14.dim("The Chief of Staff will facilitate a discussion with".padEnd(55)) + chalk14.bold("\u2551"));
2445
- console.log(chalk14.bold(" \u2551 ") + chalk14.dim("the full NEXUS org to refine your idea. When ready,".padEnd(55)) + chalk14.bold("\u2551"));
2446
- console.log(chalk14.bold(" \u2551 ") + chalk14.dim("NEXUS will draft an execution plan for your review.".padEnd(55)) + chalk14.bold("\u2551"));
2447
- console.log(chalk14.bold(" \u2551 ") + chalk14.dim("Type 'exit' to end brainstorm. Type 'plan' to hand off.".padEnd(55)) + chalk14.bold("\u2551"));
2448
- console.log(chalk14.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"));
2590
+ console.log(chalk15.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"));
2591
+ console.log(chalk15.bold(" \u2551 ") + chalk15.bold.cyan("NEXUS Brainstorm Session") + chalk15.bold(" \u2551"));
2592
+ console.log(chalk15.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"));
2593
+ console.log(chalk15.bold(" \u2551 ") + chalk15.dim("The Chief of Staff will facilitate a discussion with".padEnd(55)) + chalk15.bold("\u2551"));
2594
+ console.log(chalk15.bold(" \u2551 ") + chalk15.dim("the full NEXUS org to refine your idea. When ready,".padEnd(55)) + chalk15.bold("\u2551"));
2595
+ console.log(chalk15.bold(" \u2551 ") + chalk15.dim("NEXUS will draft an execution plan for your review.".padEnd(55)) + chalk15.bold("\u2551"));
2596
+ console.log(chalk15.bold(" \u2551 ") + chalk15.dim("Type 'exit' to end brainstorm. Type 'plan' to hand off.".padEnd(55)) + chalk15.bold("\u2551"));
2597
+ console.log(chalk15.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"));
2449
2598
  console.log("");
2450
2599
  const { input: input5 } = await import("@inquirer/prompts");
2451
2600
  const idea = await input5({ message: "What would you like to brainstorm?" });
@@ -2458,12 +2607,12 @@ var shellCommand2 = new Command13("shell").description("Launch the interactive N
2458
2607
  brainstormSpinner.stop();
2459
2608
  brainstormSpinner.clear();
2460
2609
  console.log("");
2461
- console.log(chalk14.bold.cyan(" Chief of Staff:"));
2610
+ console.log(chalk15.bold.cyan(" Chief of Staff:"));
2462
2611
  for (const line of redact(response).split("\n")) {
2463
- console.log(chalk14.white(" " + line));
2612
+ console.log(chalk15.white(" " + line));
2464
2613
  }
2465
2614
  console.log("");
2466
- const followUp = await input5({ message: chalk14.bold("You:") });
2615
+ const followUp = await input5({ message: chalk15.bold("You:") });
2467
2616
  const trimmed = followUp.trim().toLowerCase();
2468
2617
  if (!trimmed || trimmed === "exit" || trimmed === "quit") {
2469
2618
  console.log("");
@@ -2477,9 +2626,9 @@ var shellCommand2 = new Command13("shell").description("Launch the interactive N
2477
2626
  planSpinner.stop();
2478
2627
  planSpinner.clear();
2479
2628
  console.log("");
2480
- console.log(chalk14.bold.green(" Execution Plan:"));
2629
+ console.log(chalk15.bold.green(" Execution Plan:"));
2481
2630
  for (const line of redact(planResponse).split("\n")) {
2482
- console.log(chalk14.white(" " + line));
2631
+ console.log(chalk15.white(" " + line));
2483
2632
  }
2484
2633
  console.log("");
2485
2634
  log.success("Plan drafted. Use the shell to refine or approve.");
@@ -2519,10 +2668,10 @@ var shellCommand2 = new Command13("shell").description("Launch the interactive N
2519
2668
  handler: async () => {
2520
2669
  const { stdout } = await sshExec(config.sshPort, "tail -30 /home/nexus/.nexus/logs/server.log 2>/dev/null");
2521
2670
  console.log("");
2522
- console.log(chalk14.bold(" Recent Logs:"));
2523
- console.log(chalk14.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2671
+ console.log(chalk15.bold(" Recent Logs:"));
2672
+ console.log(chalk15.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2524
2673
  for (const line of redact(stdout).split("\n")) {
2525
- console.log(chalk14.dim(" " + line));
2674
+ console.log(chalk15.dim(" " + line));
2526
2675
  }
2527
2676
  console.log("");
2528
2677
  }
@@ -2542,24 +2691,24 @@ var shellCommand2 = new Command13("shell").description("Launch the interactive N
2542
2691
  description: "Display the NEXUS organizational hierarchy",
2543
2692
  handler: async () => {
2544
2693
  console.log("");
2545
- console.log(chalk14.bold(" NEXUS Organizational Hierarchy"));
2546
- console.log(chalk14.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2547
- console.log(` ${chalk14.bold.white("You")} ${chalk14.dim("(CEO)")}`);
2548
- console.log(` \u2514\u2500\u2500 ${chalk14.bold.cyan("Chief of Staff")} ${chalk14.dim("\u2014 orchestrates all work, your direct interface")}`);
2549
- console.log(` \u251C\u2500\u2500 ${chalk14.bold.blue("VP Engineering")} ${chalk14.dim("\u2014 owns technical execution")}`);
2550
- console.log(` \u2502 \u251C\u2500\u2500 ${chalk14.green("Senior Engineer")} ${chalk14.dim("\xD7 8 \u2014 implementation, refactoring")}`);
2551
- console.log(` \u2502 \u251C\u2500\u2500 ${chalk14.green("Engineer")} ${chalk14.dim("\xD7 12 \u2014 feature work, bug fixes")}`);
2552
- console.log(` \u2502 \u2514\u2500\u2500 ${chalk14.hex("#FF8C00")("DevOps Engineer")} ${chalk14.dim("\xD7 4 \u2014 CI/CD, Docker, infra")}`);
2553
- console.log(` \u251C\u2500\u2500 ${chalk14.bold.magenta("VP Product")} ${chalk14.dim("\u2014 owns roadmap and priorities")}`);
2554
- console.log(` \u2502 \u251C\u2500\u2500 ${chalk14.magenta("Product Manager")} ${chalk14.dim("\xD7 3 \u2014 specs, requirements")}`);
2555
- console.log(` \u2502 \u2514\u2500\u2500 ${chalk14.magenta("Designer")} ${chalk14.dim("\xD7 2 \u2014 UI/UX, prototyping")}`);
2556
- console.log(` \u251C\u2500\u2500 ${chalk14.bold.yellow("QA Lead")} ${chalk14.dim("\u2014 owns quality assurance")}`);
2557
- console.log(` \u2502 \u2514\u2500\u2500 ${chalk14.yellow("QA Engineer")} ${chalk14.dim("\xD7 6 \u2014 testing, coverage, validation")}`);
2558
- console.log(` \u251C\u2500\u2500 ${chalk14.bold.red("Security Engineer")} ${chalk14.dim("\xD7 4 \u2014 auth, scanning, compliance")}`);
2559
- console.log(` \u2514\u2500\u2500 ${chalk14.bold.white("Knowledge Manager")} ${chalk14.dim("\u2014 RAG, documentation, learning")}`);
2694
+ console.log(chalk15.bold(" NEXUS Organizational Hierarchy"));
2695
+ console.log(chalk15.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2696
+ console.log(` ${chalk15.bold.white("You")} ${chalk15.dim("(CEO)")}`);
2697
+ console.log(` \u2514\u2500\u2500 ${chalk15.bold.cyan("Chief of Staff")} ${chalk15.dim("\u2014 orchestrates all work, your direct interface")}`);
2698
+ console.log(` \u251C\u2500\u2500 ${chalk15.bold.blue("VP Engineering")} ${chalk15.dim("\u2014 owns technical execution")}`);
2699
+ console.log(` \u2502 \u251C\u2500\u2500 ${chalk15.green("Senior Engineer")} ${chalk15.dim("\xD7 8 \u2014 implementation, refactoring")}`);
2700
+ console.log(` \u2502 \u251C\u2500\u2500 ${chalk15.green("Engineer")} ${chalk15.dim("\xD7 12 \u2014 feature work, bug fixes")}`);
2701
+ console.log(` \u2502 \u2514\u2500\u2500 ${chalk15.hex("#FF8C00")("DevOps Engineer")} ${chalk15.dim("\xD7 4 \u2014 CI/CD, Docker, infra")}`);
2702
+ console.log(` \u251C\u2500\u2500 ${chalk15.bold.magenta("VP Product")} ${chalk15.dim("\u2014 owns roadmap and priorities")}`);
2703
+ console.log(` \u2502 \u251C\u2500\u2500 ${chalk15.magenta("Product Manager")} ${chalk15.dim("\xD7 3 \u2014 specs, requirements")}`);
2704
+ console.log(` \u2502 \u2514\u2500\u2500 ${chalk15.magenta("Designer")} ${chalk15.dim("\xD7 2 \u2014 UI/UX, prototyping")}`);
2705
+ console.log(` \u251C\u2500\u2500 ${chalk15.bold.yellow("QA Lead")} ${chalk15.dim("\u2014 owns quality assurance")}`);
2706
+ console.log(` \u2502 \u2514\u2500\u2500 ${chalk15.yellow("QA Engineer")} ${chalk15.dim("\xD7 6 \u2014 testing, coverage, validation")}`);
2707
+ console.log(` \u251C\u2500\u2500 ${chalk15.bold.red("Security Engineer")} ${chalk15.dim("\xD7 4 \u2014 auth, scanning, compliance")}`);
2708
+ console.log(` \u2514\u2500\u2500 ${chalk15.bold.white("Knowledge Manager")} ${chalk15.dim("\u2014 RAG, documentation, learning")}`);
2560
2709
  console.log("");
2561
- console.log(chalk14.dim(" 56 agents total \xB7 Self-learning ML pipeline"));
2562
- console.log(chalk14.dim(" Full details: https://buildwithnexus.dev/overview"));
2710
+ console.log(chalk15.dim(" 56 agents total \xB7 Self-learning ML pipeline"));
2711
+ console.log(chalk15.dim(" Full details: https://buildwithnexus.dev/overview"));
2563
2712
  console.log("");
2564
2713
  }
2565
2714
  });
@@ -2648,14 +2797,14 @@ var shellCommand2 = new Command13("shell").description("Launch the interactive N
2648
2797
  for (let i = 0; i < steps.length; i++) {
2649
2798
  const step = steps[i];
2650
2799
  console.log("");
2651
- console.log(chalk14.bold(` \u2500\u2500 ${chalk14.cyan(`Step ${i + 1}/${steps.length}`)} \u2500\u2500 ${step.title} \u2500\u2500`));
2800
+ console.log(chalk15.bold(` \u2500\u2500 ${chalk15.cyan(`Step ${i + 1}/${steps.length}`)} \u2500\u2500 ${step.title} \u2500\u2500`));
2652
2801
  console.log("");
2653
2802
  for (const line of step.content) {
2654
- console.log(chalk14.white(" " + line));
2803
+ console.log(chalk15.white(" " + line));
2655
2804
  }
2656
2805
  console.log("");
2657
2806
  if (i < steps.length - 1) {
2658
- const next = await input5({ message: chalk14.dim("Press Enter to continue (or 'skip' to exit)") });
2807
+ const next = await input5({ message: chalk15.dim("Press Enter to continue (or 'skip' to exit)") });
2659
2808
  if (next.trim().toLowerCase() === "skip") {
2660
2809
  log.success("Tutorial ended. Type /help to see all commands.");
2661
2810
  return;
@@ -2702,9 +2851,9 @@ cli.addCommand(shellCommand2);
2702
2851
  cli.action(async () => {
2703
2852
  try {
2704
2853
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_secrets(), secrets_exports));
2705
- const { isVmRunning: isVmRunning3 } = await Promise.resolve().then(() => (init_qemu(), qemu_exports));
2854
+ const { isVmRunning: isVmRunning2 } = await Promise.resolve().then(() => (init_qemu(), qemu_exports));
2706
2855
  const config = loadConfig2();
2707
- if (config && isVmRunning3()) {
2856
+ if (config && isVmRunning2()) {
2708
2857
  await shellCommand2.parseAsync([], { from: "user" });
2709
2858
  return;
2710
2859
  }
@@ -2718,7 +2867,7 @@ import fs11 from "fs";
2718
2867
  import path12 from "path";
2719
2868
  import os3 from "os";
2720
2869
  import https from "https";
2721
- import chalk15 from "chalk";
2870
+ import chalk16 from "chalk";
2722
2871
  var PACKAGE_NAME = "buildwithnexus";
2723
2872
  var CHECK_INTERVAL_MS = 4 * 60 * 60 * 1e3;
2724
2873
  var STATE_DIR = path12.join(os3.homedir(), ".buildwithnexus");
@@ -2799,8 +2948,8 @@ async function checkForUpdates(currentVersion) {
2799
2948
  function printUpdateBanner(current, latest) {
2800
2949
  const msg = [
2801
2950
  "",
2802
- chalk15.yellow(` Update available: ${current} \u2192 ${latest}`),
2803
- chalk15.cyan(` Run: npm update -g buildwithnexus`),
2951
+ chalk16.yellow(` Update available: ${current} \u2192 ${latest}`),
2952
+ chalk16.cyan(` Run: npm update -g buildwithnexus`),
2804
2953
  ""
2805
2954
  ].join("\n");
2806
2955
  process.stderr.write(msg + "\n");