@atlashub/smartstack-cli 4.61.0 → 4.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -127429,6 +127429,49 @@ var import_cli_table34 = __toESM(require_cli_table3());
127429
127429
  var import_child_process8 = require("child_process");
127430
127430
  var import_fs_extra13 = __toESM(require_lib());
127431
127431
  var import_path13 = require("path");
127432
+ function detectPackageManager() {
127433
+ const tryCmd = (cmd) => {
127434
+ try {
127435
+ (0, import_child_process8.execSync)(`${cmd} --version`, { encoding: "utf-8", timeout: 5e3, stdio: "pipe" });
127436
+ return true;
127437
+ } catch {
127438
+ return false;
127439
+ }
127440
+ };
127441
+ if (process.platform === "win32" && tryCmd("winget")) return "winget";
127442
+ if (process.platform === "darwin" && tryCmd("brew")) return "brew";
127443
+ if (process.platform === "linux") {
127444
+ if (tryCmd("apt")) return "apt";
127445
+ if (tryCmd("dnf")) return "dnf";
127446
+ if (tryCmd("pacman")) return "pacman";
127447
+ }
127448
+ return null;
127449
+ }
127450
+ function getInstallCmd(pm, info) {
127451
+ if (!pm) return void 0;
127452
+ return info[pm];
127453
+ }
127454
+ function getContainerEngineStatus() {
127455
+ try {
127456
+ const dockerVer = (0, import_child_process8.execSync)("docker --version", { encoding: "utf-8", timeout: 5e3, stdio: "pipe" }).trim();
127457
+ const dockerInfo = (() => {
127458
+ try {
127459
+ (0, import_child_process8.execSync)("docker info", { encoding: "utf-8", timeout: 1e4, stdio: "pipe" });
127460
+ return true;
127461
+ } catch {
127462
+ return false;
127463
+ }
127464
+ })();
127465
+ return { name: "Docker", version: dockerVer.replace("Docker version ", "").split(",")[0], running: dockerInfo };
127466
+ } catch {
127467
+ }
127468
+ try {
127469
+ const podmanVer = (0, import_child_process8.execSync)("podman --version", { encoding: "utf-8", timeout: 5e3, stdio: "pipe" }).trim();
127470
+ return { name: "Podman", version: podmanVer.replace("podman version ", ""), running: true };
127471
+ } catch {
127472
+ }
127473
+ return null;
127474
+ }
127432
127475
  function getNodeVersion() {
127433
127476
  return process.version;
127434
127477
  }
@@ -127468,9 +127511,10 @@ function getNpmVersion() {
127468
127511
  return null;
127469
127512
  }
127470
127513
  }
127471
- var doctorCommand = new Command("doctor").description("Run diagnostics and check SmartStack health").option("--json", "Output as JSON").option("-v, --verbose", "Show detailed information").action(async (options) => {
127514
+ var doctorCommand = new Command("doctor").description("Run diagnostics and check SmartStack health").option("--json", "Output as JSON").option("-v, --verbose", "Show detailed information").option("--fix", "Auto-install missing tools using system package manager").action(async (options) => {
127472
127515
  const diagnostics = [];
127473
127516
  const pkg2 = JSON.parse(await import_fs_extra13.default.readFile((0, import_path13.join)(__dirname, "..", "package.json"), "utf-8"));
127517
+ const pm = options.fix ? detectPackageManager() : null;
127474
127518
  if (!options.json) {
127475
127519
  console.log(source_default.cyan(`
127476
127520
  \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
@@ -127559,7 +127603,14 @@ var doctorCommand = new Command("doctor").description("Run diagnostics and check
127559
127603
  name: "Git",
127560
127604
  status: gitVersion ? "ok" : "error",
127561
127605
  message: gitVersion || "Not installed",
127562
- fix: !gitVersion ? "Install Git: https://git-scm.com/" : void 0
127606
+ fix: !gitVersion ? "Install Git: https://git-scm.com/" : void 0,
127607
+ installCmd: !gitVersion ? getInstallCmd(pm, {
127608
+ winget: "winget install -e --id Git.Git",
127609
+ brew: "brew install git",
127610
+ apt: "sudo apt install -y git",
127611
+ dnf: "sudo dnf install -y git",
127612
+ pacman: "sudo pacman -S --noconfirm git"
127613
+ }) : void 0
127563
127614
  });
127564
127615
  const dotnetVersion = getDotNetVersion();
127565
127616
  diagnostics.push({
@@ -127567,8 +127618,51 @@ var doctorCommand = new Command("doctor").description("Run diagnostics and check
127567
127618
  status: dotnetVersion ? "ok" : "warning",
127568
127619
  message: dotnetVersion || "Not installed",
127569
127620
  details: !dotnetVersion ? "Required for .NET projects" : void 0,
127570
- fix: !dotnetVersion ? "Install .NET SDK: https://dotnet.microsoft.com/" : void 0
127621
+ fix: !dotnetVersion ? "Install .NET SDK: https://dotnet.microsoft.com/" : void 0,
127622
+ installCmd: !dotnetVersion ? getInstallCmd(pm, {
127623
+ winget: "winget install -e --id Microsoft.DotNet.SDK.9",
127624
+ brew: "brew install dotnet",
127625
+ apt: "sudo apt install -y dotnet-sdk-9.0",
127626
+ dnf: "sudo dnf install -y dotnet-sdk-9.0"
127627
+ }) : void 0
127571
127628
  });
127629
+ const containerEngine = getContainerEngineStatus();
127630
+ if (containerEngine && containerEngine.running) {
127631
+ diagnostics.push({
127632
+ name: "Container Engine",
127633
+ status: "ok",
127634
+ message: `${containerEngine.name} ${containerEngine.version}`
127635
+ });
127636
+ } else if (containerEngine && !containerEngine.running) {
127637
+ diagnostics.push({
127638
+ name: "Container Engine",
127639
+ status: "warning",
127640
+ message: `${containerEngine.name} installed but daemon not running`,
127641
+ fix: "Start Docker Desktop, or install Podman (daemonless)",
127642
+ installCmd: getInstallCmd(pm, {
127643
+ winget: "winget install -e --id RedHat.Podman",
127644
+ brew: "brew install podman",
127645
+ apt: "sudo apt install -y podman",
127646
+ dnf: "sudo dnf install -y podman",
127647
+ pacman: "sudo pacman -S --noconfirm podman"
127648
+ })
127649
+ });
127650
+ } else {
127651
+ diagnostics.push({
127652
+ name: "Container Engine",
127653
+ status: "warning",
127654
+ message: "Not installed (Docker or Podman)",
127655
+ details: "Required for ss docker commands",
127656
+ fix: "Install Docker Desktop or Podman",
127657
+ installCmd: getInstallCmd(pm, {
127658
+ winget: "winget install -e --id RedHat.Podman",
127659
+ brew: "brew install podman",
127660
+ apt: "sudo apt install -y podman",
127661
+ dnf: "sudo dnf install -y podman",
127662
+ pacman: "sudo pacman -S --noconfirm podman"
127663
+ })
127664
+ });
127665
+ }
127572
127666
  const claudeInstalled = isClaudeCodeInstalled();
127573
127667
  const claudeVersion = getClaudeCodeVersion();
127574
127668
  diagnostics.push({
@@ -127701,12 +127795,48 @@ ${source_default.gray(item.details)}`;
127701
127795
  if (errorCount > 0) console.log(` ${source_default.red("\u2717")} ${errorCount} Errors`);
127702
127796
  console.log();
127703
127797
  const itemsWithFixes = diagnostics.filter((d) => d.fix && (d.status === "error" || d.status === "warning"));
127704
- if (itemsWithFixes.length > 0) {
127798
+ if (itemsWithFixes.length > 0 && !options.fix) {
127705
127799
  console.log(source_default.bold("Recommended fixes:"));
127706
127800
  for (const item of itemsWithFixes) {
127707
127801
  console.log(` ${item.name}: ${source_default.cyan(item.fix)}`);
127708
127802
  }
127709
127803
  console.log();
127804
+ const fixableCount = diagnostics.filter((d) => d.installCmd).length;
127805
+ if (fixableCount > 0) {
127806
+ console.log(source_default.gray(` Tip: Run ${source_default.cyan("ss doctor --fix")} to auto-install ${fixableCount} missing tool(s)`));
127807
+ console.log();
127808
+ }
127809
+ }
127810
+ if (options.fix) {
127811
+ const fixable = diagnostics.filter((d) => d.installCmd && (d.status === "error" || d.status === "warning"));
127812
+ if (fixable.length === 0) {
127813
+ console.log(source_default.green("Nothing to fix \u2014 all installable tools are present."));
127814
+ console.log();
127815
+ } else if (!pm) {
127816
+ logger.error("No supported package manager found (winget, brew, apt, dnf, pacman).");
127817
+ console.log(` Please install the missing tools manually.`);
127818
+ console.log();
127819
+ } else {
127820
+ console.log(source_default.bold(`Auto-fix using ${source_default.cyan(pm)}:`));
127821
+ console.log();
127822
+ let fixed = 0;
127823
+ for (const item of fixable) {
127824
+ console.log(` ${source_default.yellow("Installing")} ${item.name}: ${source_default.gray(item.installCmd)}`);
127825
+ try {
127826
+ (0, import_child_process8.execSync)(item.installCmd, { encoding: "utf-8", stdio: "inherit", timeout: 3e5 });
127827
+ console.log(` ${source_default.green("\u2713")} ${item.name} installed`);
127828
+ fixed++;
127829
+ } catch {
127830
+ console.log(` ${source_default.red("\u2717")} ${item.name} install failed \u2014 try manually: ${source_default.cyan(item.installCmd)}`);
127831
+ }
127832
+ console.log();
127833
+ }
127834
+ console.log(source_default.bold(`Fixed: ${fixed}/${fixable.length}`));
127835
+ if (fixed > 0) {
127836
+ console.log(source_default.gray(" Restart your terminal, then run ss doctor to verify."));
127837
+ }
127838
+ console.log();
127839
+ }
127710
127840
  }
127711
127841
  if (errorCount === 0) {
127712
127842
  logger.box([
@@ -129971,46 +130101,57 @@ tmuxCommand.command("status").description("Show WSL development environment stat
129971
130101
  var import_child_process12 = require("child_process");
129972
130102
  var import_path18 = require("path");
129973
130103
  var import_fs_extra16 = __toESM(require_lib());
129974
- function checkDocker() {
130104
+ function checkEngine(name) {
129975
130105
  try {
129976
- const version2 = (0, import_child_process12.spawnSync)("docker", ["--version"], {
130106
+ const version2 = (0, import_child_process12.spawnSync)(name, ["--version"], {
129977
130107
  encoding: "utf-8",
129978
130108
  shell: true,
129979
130109
  timeout: 5e3,
129980
130110
  stdio: "pipe"
129981
130111
  });
129982
130112
  if (version2.status !== 0) {
129983
- return { installed: false, running: false };
130113
+ return { name, installed: false, running: false };
130114
+ }
130115
+ if (name === "podman") {
130116
+ return { name, installed: true, running: true };
129984
130117
  }
129985
- const info = (0, import_child_process12.spawnSync)("docker", ["info"], {
130118
+ const info = (0, import_child_process12.spawnSync)(name, ["info"], {
129986
130119
  encoding: "utf-8",
129987
130120
  shell: true,
129988
130121
  timeout: 1e4,
129989
130122
  stdio: "pipe"
129990
130123
  });
129991
- return { installed: true, running: info.status === 0 };
130124
+ return { name, installed: true, running: info.status === 0 };
129992
130125
  } catch {
129993
- return { installed: false, running: false };
130126
+ return { name, installed: false, running: false };
129994
130127
  }
129995
130128
  }
129996
- function requireDocker() {
129997
- const status = checkDocker();
129998
- if (!status.installed) {
129999
- logger.error("Docker is not installed.");
130129
+ function detectEngine() {
130130
+ const docker = checkEngine("docker");
130131
+ if (docker.installed && docker.running) return docker;
130132
+ const podman = checkEngine("podman");
130133
+ if (podman.installed && podman.running) {
130134
+ logger.info(`Using ${source_default.cyan("Podman")} (Docker not found or not running)`);
130135
+ return podman;
130136
+ }
130137
+ if (docker.installed && !docker.running) {
130138
+ logger.error("Docker is installed but the daemon is not running, and Podman is not available.");
130000
130139
  console.log();
130001
- console.log(` Install Docker Desktop: ${source_default.cyan("https://docs.docker.com/get-docker/")}`);
130002
- console.log(` Then restart your terminal and try again.`);
130140
+ console.log(` Option 1: Start Docker Desktop and wait for it to be ready`);
130141
+ console.log(` Option 2: Install Podman (daemonless): ${source_default.cyan("https://podman.io/docs/installation")}`);
130003
130142
  console.log();
130004
- return false;
130005
- }
130006
- if (!status.running) {
130007
- logger.error("Docker is installed but the daemon is not running.");
130008
- console.log();
130009
- console.log(` Start Docker Desktop and wait for it to be ready, then try again.`);
130010
- console.log();
130011
- return false;
130143
+ return null;
130012
130144
  }
130013
- return true;
130145
+ logger.error("No container engine found (Docker or Podman).");
130146
+ console.log();
130147
+ console.log(` Install one of the following:`);
130148
+ console.log(` Docker Desktop: ${source_default.cyan("https://docs.docker.com/get-docker/")}`);
130149
+ console.log(` Podman: ${source_default.cyan("https://podman.io/docs/installation")}`);
130150
+ console.log();
130151
+ return null;
130152
+ }
130153
+ function requireEngine() {
130154
+ return detectEngine();
130014
130155
  }
130015
130156
  function findComposeFile() {
130016
130157
  const cwd = process.cwd();
@@ -130032,8 +130173,8 @@ function requireComposeFile() {
130032
130173
  }
130033
130174
  return composePath;
130034
130175
  }
130035
- function runCompose(composePath, args) {
130036
- const result = (0, import_child_process12.spawnSync)("docker", ["compose", "-f", composePath, ...args], {
130176
+ function runCompose(engine, composePath, args) {
130177
+ const result = (0, import_child_process12.spawnSync)(engine.name, ["compose", "-f", composePath, ...args], {
130037
130178
  encoding: "utf-8",
130038
130179
  shell: true,
130039
130180
  stdio: "inherit",
@@ -130041,68 +130182,73 @@ function runCompose(composePath, args) {
130041
130182
  });
130042
130183
  return result.status ?? 1;
130043
130184
  }
130044
- var dockerCommand = new Command("docker").description("Build and run SmartStack Docker images").addCommand(
130185
+ var dockerCommand = new Command("docker").description("Build and run SmartStack Docker images (Docker or Podman)").addCommand(
130045
130186
  new Command("up").description("Build images and start containers").option("-d, --detach", "Run containers in the background").option("--no-build", "Skip image build, use existing images").action(async (options) => {
130046
- if (!requireDocker()) return;
130187
+ const engine = requireEngine();
130188
+ if (!engine) return;
130047
130189
  const composePath = requireComposeFile();
130048
130190
  if (!composePath) return;
130049
130191
  logger.header("SmartStack Docker Up");
130050
130192
  const args = ["up"];
130051
130193
  if (options.build !== false) args.push("--build");
130052
130194
  if (options.detach) args.push("-d");
130053
- const code = runCompose(composePath, args);
130195
+ const code = runCompose(engine, composePath, args);
130054
130196
  if (code !== 0) {
130055
- logger.error(`docker compose up exited with code ${code}`);
130197
+ logger.error(`${engine.name} compose up exited with code ${code}`);
130056
130198
  process.exitCode = code;
130057
130199
  }
130058
130200
  })
130059
130201
  ).addCommand(
130060
130202
  new Command("down").description("Stop and remove containers").option("-v, --volumes", "Also remove volumes").action(async (options) => {
130061
- if (!requireDocker()) return;
130203
+ const engine = requireEngine();
130204
+ if (!engine) return;
130062
130205
  const composePath = requireComposeFile();
130063
130206
  if (!composePath) return;
130064
130207
  logger.header("SmartStack Docker Down");
130065
130208
  const args = ["down"];
130066
130209
  if (options.volumes) args.push("-v");
130067
- const code = runCompose(composePath, args);
130210
+ const code = runCompose(engine, composePath, args);
130068
130211
  if (code !== 0) {
130069
- logger.error(`docker compose down exited with code ${code}`);
130212
+ logger.error(`${engine.name} compose down exited with code ${code}`);
130070
130213
  process.exitCode = code;
130071
130214
  }
130072
130215
  })
130073
130216
  ).addCommand(
130074
130217
  new Command("build").description("Build images without starting containers").option("--no-cache", "Build without using cache").action(async (options) => {
130075
- if (!requireDocker()) return;
130218
+ const engine = requireEngine();
130219
+ if (!engine) return;
130076
130220
  const composePath = requireComposeFile();
130077
130221
  if (!composePath) return;
130078
130222
  logger.header("SmartStack Docker Build");
130079
130223
  const args = ["build"];
130080
130224
  if (options.cache === false) args.push("--no-cache");
130081
- const code = runCompose(composePath, args);
130225
+ const code = runCompose(engine, composePath, args);
130082
130226
  if (code !== 0) {
130083
- logger.error(`docker compose build exited with code ${code}`);
130227
+ logger.error(`${engine.name} compose build exited with code ${code}`);
130084
130228
  process.exitCode = code;
130085
130229
  }
130086
130230
  })
130087
130231
  ).addCommand(
130088
130232
  new Command("status").description("Show container status").action(async () => {
130089
- if (!requireDocker()) return;
130233
+ const engine = requireEngine();
130234
+ if (!engine) return;
130090
130235
  const composePath = requireComposeFile();
130091
130236
  if (!composePath) return;
130092
- const code = runCompose(composePath, ["ps", "-a"]);
130237
+ const code = runCompose(engine, composePath, ["ps", "-a"]);
130093
130238
  if (code !== 0) {
130094
130239
  process.exitCode = code;
130095
130240
  }
130096
130241
  })
130097
130242
  ).addCommand(
130098
130243
  new Command("logs").description("Show container logs").option("-f, --follow", "Follow log output").option("--tail <lines>", "Number of lines to show from the end", "100").argument("[service]", "Service name (backend or frontend)").action(async (service, options) => {
130099
- if (!requireDocker()) return;
130244
+ const engine = requireEngine();
130245
+ if (!engine) return;
130100
130246
  const composePath = requireComposeFile();
130101
130247
  if (!composePath) return;
130102
130248
  const args = ["logs", "--tail", options.tail];
130103
130249
  if (options.follow) args.push("-f");
130104
130250
  if (service) args.push(service);
130105
- const code = runCompose(composePath, args);
130251
+ const code = runCompose(engine, composePath, args);
130106
130252
  if (code !== 0) {
130107
130253
  process.exitCode = code;
130108
130254
  }
@@ -130120,21 +130266,21 @@ async function main2() {
130120
130266
  const program2 = new Command();
130121
130267
  program2.name("smartstack").description(source_default.cyan("SmartStack Claude Code automation toolkit")).version(pkg.version, "-v, --version");
130122
130268
  program2.addCommand(createLicenseCommand());
130123
- program2.addCommand(installCommand);
130124
- program2.addCommand(uninstallCommand);
130125
- program2.addCommand(statusCommand);
130126
- program2.addCommand(updateCommand);
130127
- program2.addCommand(docsCommand);
130128
- program2.addCommand(initCommand);
130129
- program2.addCommand(upgradeCommand);
130269
+ program2.addCommand(adminCommand);
130270
+ program2.addCommand(businessAnalyseHandoffCommand);
130130
130271
  program2.addCommand(checkMcpCommand);
130131
- program2.addCommand(ralphCommand);
130272
+ program2.addCommand(dockerCommand);
130132
130273
  program2.addCommand(doctorCommand);
130133
- program2.addCommand(adminCommand);
130274
+ program2.addCommand(docsCommand);
130275
+ program2.addCommand(initCommand);
130276
+ program2.addCommand(installCommand);
130134
130277
  program2.addCommand(mcpCommand);
130135
- program2.addCommand(businessAnalyseHandoffCommand);
130278
+ program2.addCommand(ralphCommand);
130279
+ program2.addCommand(statusCommand);
130136
130280
  program2.addCommand(tmuxCommand);
130137
- program2.addCommand(dockerCommand);
130281
+ program2.addCommand(uninstallCommand);
130282
+ program2.addCommand(updateCommand);
130283
+ program2.addCommand(upgradeCommand);
130138
130284
  const args = process.argv.slice(2);
130139
130285
  const commandName = args[0] || "";
130140
130286
  const requiresLicense = !LICENSE_FREE_COMMANDS.some(