@atlashub/smartstack-cli 3.3.1 → 3.4.1

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
@@ -44464,16 +44464,16 @@ var require_chainedTokenCredential = __commonJS({
44464
44464
  // node_modules/uuid/dist/esm-node/rng.js
44465
44465
  function rng() {
44466
44466
  if (poolPtr > rnds8Pool.length - 16) {
44467
- import_crypto2.default.randomFillSync(rnds8Pool);
44467
+ import_crypto4.default.randomFillSync(rnds8Pool);
44468
44468
  poolPtr = 0;
44469
44469
  }
44470
44470
  return rnds8Pool.slice(poolPtr, poolPtr += 16);
44471
44471
  }
44472
- var import_crypto2, rnds8Pool, poolPtr;
44472
+ var import_crypto4, rnds8Pool, poolPtr;
44473
44473
  var init_rng = __esm({
44474
44474
  "node_modules/uuid/dist/esm-node/rng.js"() {
44475
44475
  "use strict";
44476
- import_crypto2 = __toESM(require("crypto"));
44476
+ import_crypto4 = __toESM(require("crypto"));
44477
44477
  rnds8Pool = new Uint8Array(256);
44478
44478
  poolPtr = rnds8Pool.length;
44479
44479
  }
@@ -44678,13 +44678,13 @@ function md5(bytes) {
44678
44678
  } else if (typeof bytes === "string") {
44679
44679
  bytes = Buffer.from(bytes, "utf8");
44680
44680
  }
44681
- return import_crypto3.default.createHash("md5").update(bytes).digest();
44681
+ return import_crypto5.default.createHash("md5").update(bytes).digest();
44682
44682
  }
44683
- var import_crypto3, md5_default;
44683
+ var import_crypto5, md5_default;
44684
44684
  var init_md5 = __esm({
44685
44685
  "node_modules/uuid/dist/esm-node/md5.js"() {
44686
44686
  "use strict";
44687
- import_crypto3 = __toESM(require("crypto"));
44687
+ import_crypto5 = __toESM(require("crypto"));
44688
44688
  md5_default = md5;
44689
44689
  }
44690
44690
  });
@@ -44733,13 +44733,13 @@ function sha1(bytes) {
44733
44733
  } else if (typeof bytes === "string") {
44734
44734
  bytes = Buffer.from(bytes, "utf8");
44735
44735
  }
44736
- return import_crypto4.default.createHash("sha1").update(bytes).digest();
44736
+ return import_crypto6.default.createHash("sha1").update(bytes).digest();
44737
44737
  }
44738
- var import_crypto4, sha1_default;
44738
+ var import_crypto6, sha1_default;
44739
44739
  var init_sha1 = __esm({
44740
44740
  "node_modules/uuid/dist/esm-node/sha1.js"() {
44741
44741
  "use strict";
44742
- import_crypto4 = __toESM(require("crypto"));
44742
+ import_crypto6 = __toESM(require("crypto"));
44743
44743
  sha1_default = sha1;
44744
44744
  }
44745
44745
  });
@@ -115955,6 +115955,7 @@ var import_fs_extra5 = __toESM(require_lib());
115955
115955
  var import_path6 = require("path");
115956
115956
  var import_os3 = require("os");
115957
115957
  var import_child_process5 = require("child_process");
115958
+ var import_crypto2 = require("crypto");
115958
115959
 
115959
115960
  // src/lib/file-tracker.ts
115960
115961
  var import_crypto = require("crypto");
@@ -116688,7 +116689,8 @@ EndGlobal
116688
116689
  throw new Error(`Template not found: ${templatePath}`);
116689
116690
  }
116690
116691
  let appSettingsContent = await import_fs_extra5.default.readFile(templatePath, "utf-8");
116691
- appSettingsContent = appSettingsContent.replace(/\{\{ProjectName\}\}/g, projectName).replace(/\{\{ProjectDomain\}\}/g, `${projectName.toLowerCase()}.app`).replace(/\{\{ProjectNameLower\}\}/g, projectName.toLowerCase());
116692
+ const jwtSecret = (0, import_crypto2.randomBytes)(64).toString("base64");
116693
+ appSettingsContent = appSettingsContent.replace(/\{\{ProjectName\}\}/g, projectName).replace(/\{\{ProjectDomain\}\}/g, `${projectName.toLowerCase()}.app`).replace(/\{\{ProjectNameLower\}\}/g, projectName.toLowerCase()).replace(/\{\{JwtSecret\}\}/g, jwtSecret);
116692
116694
  const appSettings = JSON.parse(appSettingsContent);
116693
116695
  appSettings.MultiTenant = {
116694
116696
  Enabled: config.multiTenant.enabled,
@@ -124559,6 +124561,7 @@ var glob = Object.assign(glob_, {
124559
124561
  glob.glob = glob;
124560
124562
 
124561
124563
  // src/lib/config-sync.ts
124564
+ var import_crypto3 = require("crypto");
124562
124565
  function addMissingKeys(target, template, prefix = "") {
124563
124566
  const added = [];
124564
124567
  for (const key of Object.keys(template)) {
@@ -124578,7 +124581,7 @@ function addMissingKeys(target, template, prefix = "") {
124578
124581
  return added;
124579
124582
  }
124580
124583
  function resolveTemplatePlaceholders(content, projectName) {
124581
- return content.replace(/\{\{ProjectName\}\}/g, projectName).replace(/\{\{ProjectDomain\}\}/g, `${projectName.toLowerCase()}.app`).replace(/\{\{ProjectNameLower\}\}/g, projectName.toLowerCase());
124584
+ return content.replace(/\{\{ProjectName\}\}/g, projectName).replace(/\{\{ProjectDomain\}\}/g, `${projectName.toLowerCase()}.app`).replace(/\{\{ProjectNameLower\}\}/g, projectName.toLowerCase()).replace(/\{\{JwtSecret\}\}/g, (0, import_crypto3.randomBytes)(64).toString("base64"));
124582
124585
  }
124583
124586
  function isPlainObject(value) {
124584
124587
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -124888,6 +124891,30 @@ async function syncAppSettings(projectDir, baseNamespace, dryRun) {
124888
124891
  }
124889
124892
  return added;
124890
124893
  }
124894
+ async function syncClaudeSettings(projectDir, dryRun) {
124895
+ const settingsPath = (0, import_path7.join)(projectDir, ".claude", "settings.json");
124896
+ const templatePath = (0, import_path7.join)(TEMPLATES_DIR3, "claude-settings.json.template");
124897
+ if (!await import_fs_extra6.default.pathExists(templatePath)) {
124898
+ logger.debug("claude-settings.json.template not found, skipping");
124899
+ return [];
124900
+ }
124901
+ const templateContent = await import_fs_extra6.default.readFile(templatePath, "utf-8");
124902
+ const templateJson = JSON.parse(templateContent);
124903
+ let clientJson = {};
124904
+ if (await import_fs_extra6.default.pathExists(settingsPath)) {
124905
+ const clientContent = await import_fs_extra6.default.readFile(settingsPath, "utf-8");
124906
+ clientJson = JSON.parse(clientContent);
124907
+ }
124908
+ const added = addMissingKeys(clientJson, templateJson);
124909
+ if (added.length === 0) {
124910
+ return [];
124911
+ }
124912
+ if (!dryRun) {
124913
+ await import_fs_extra6.default.ensureDir((0, import_path7.join)(projectDir, ".claude"));
124914
+ await import_fs_extra6.default.writeFile(settingsPath, JSON.stringify(clientJson, null, 2) + "\n");
124915
+ }
124916
+ return added;
124917
+ }
124891
124918
  var upgradeCommand = new Command("upgrade").description("Upgrade SmartStack packages to the latest version").option("--preview", "Upgrade to latest preview/prerelease version").option("--dry-run", "Show what would be upgraded without actually upgrading").action(async (options) => {
124892
124919
  logger.header("SmartStack Package Upgrade");
124893
124920
  const dryRun = options.dryRun || false;
@@ -124901,6 +124928,7 @@ var upgradeCommand = new Command("upgrade").description("Upgrade SmartStack pack
124901
124928
  npmUpgraded: false,
124902
124929
  npmSkipped: false,
124903
124930
  configSynced: 0,
124931
+ claudeSettingsSynced: 0,
124904
124932
  programCsIssues: []
124905
124933
  };
124906
124934
  if (dryRun) {
@@ -125092,6 +125120,22 @@ var upgradeCommand = new Command("upgrade").description("Upgrade SmartStack pack
125092
125120
  logger.info(`appsettings.json ${source_default.green("\u2713")} up to date`);
125093
125121
  console.log();
125094
125122
  }
125123
+ logger.info("Syncing .claude/settings.json...");
125124
+ const addedClaudeKeys = await syncClaudeSettings(projectDir, dryRun);
125125
+ result.claudeSettingsSynced = addedClaudeKeys.length;
125126
+ if (addedClaudeKeys.length > 0) {
125127
+ if (dryRun) {
125128
+ logger.warning(`[DRY RUN] Would add ${addedClaudeKeys.length} new setting(s) to .claude/settings.json`);
125129
+ }
125130
+ for (const key of addedClaudeKeys) {
125131
+ logger.info(` ${source_default.green("+")} ${key}`);
125132
+ }
125133
+ logger.success(`${addedClaudeKeys.length} new setting(s) added to .claude/settings.json`);
125134
+ console.log();
125135
+ } else {
125136
+ logger.info(`.claude/settings.json ${source_default.green("\u2713")} up to date`);
125137
+ console.log();
125138
+ }
125095
125139
  logger.info("Validating Program.cs...");
125096
125140
  result.programCsIssues = await validateProgramCs(projectDir, config.baseNamespace);
125097
125141
  if (result.programCsIssues.length > 0) {
@@ -125119,7 +125163,7 @@ var upgradeCommand = new Command("upgrade").description("Upgrade SmartStack pack
125119
125163
  logger.success(`Updated config version to ${source_default.cyan(nugetVersion)}`);
125120
125164
  console.log();
125121
125165
  }
125122
- const totalChanged = result.nugetUpgraded + result.otherPkgUpdated + (result.npmUpgraded ? 1 : 0) + migrationSummary.totalApplied + result.configSynced;
125166
+ const totalChanged = result.nugetUpgraded + result.otherPkgUpdated + (result.npmUpgraded ? 1 : 0) + migrationSummary.totalApplied + result.configSynced + result.claudeSettingsSynced;
125123
125167
  const allUpToDate = totalChanged === 0 && result.nugetFailed === 0 && result.otherPkgFailed === 0;
125124
125168
  const hasProgramIssues = result.programCsIssues.length > 0;
125125
125169
  if (allUpToDate && !hasProgramIssues) {
@@ -125174,6 +125218,9 @@ var upgradeCommand = new Command("upgrade").description("Upgrade SmartStack pack
125174
125218
  if (result.configSynced > 0) {
125175
125219
  lines.push(` ${source_default.green("\u2713")} Config: ${result.configSynced} new setting(s) added`);
125176
125220
  }
125221
+ if (result.claudeSettingsSynced > 0) {
125222
+ lines.push(` ${source_default.green("\u2713")} Claude: ${result.claudeSettingsSynced} new setting(s) added`);
125223
+ }
125177
125224
  if (result.programCsIssues.length > 0) {
125178
125225
  lines.push(` ${source_default.red("\u26A0")} Program.cs: ${result.programCsIssues.length} missing call(s) - manual fix required`);
125179
125226
  }
@@ -126978,6 +127025,12 @@ function checkClaudeInWsl() {
126978
127025
  const match2 = out.match(/(\d+\.\d+\.\d+)/);
126979
127026
  return { installed: true, version: match2 ? match2[1] : out };
126980
127027
  }
127028
+ function checkSmartStackInWsl() {
127029
+ const out = wslExec("source ~/.nvm/nvm.sh 2>/dev/null; ss --version 2>/dev/null");
127030
+ if (!out) return { installed: false, version: null };
127031
+ const match2 = out.match(/(\d+\.\d+\.\d+)/);
127032
+ return { installed: true, version: match2 ? match2[1] : out };
127033
+ }
126981
127034
  async function installGitInWsl() {
126982
127035
  const status = checkGitInWsl();
126983
127036
  if (status.installed) return { success: true, version: status.version, skipped: true };
@@ -127071,7 +127124,8 @@ async function installDotnetInWsl() {
127071
127124
  return { success: false, error: "dotnet-install.sh failed" };
127072
127125
  }
127073
127126
  wslInstall(
127074
- `grep -q .dotnet ~/.bashrc || echo 'export PATH="$PATH:$HOME/.dotnet"' >> ~/.bashrc`,
127127
+ `grep -q .dotnet ~/.bashrc || echo 'export DOTNET_ROOT="$HOME/.dotnet"
127128
+ export PATH="$PATH:$HOME/.dotnet:$HOME/.dotnet/tools"' >> ~/.bashrc`,
127075
127129
  5e3
127076
127130
  );
127077
127131
  const check = checkDotnetInWsl();
@@ -127106,6 +127160,63 @@ async function installClaudeInWsl() {
127106
127160
  spinner.fail("Claude Code installation could not be verified");
127107
127161
  return { success: false, error: "Verification failed after install" };
127108
127162
  }
127163
+ async function installSmartStackInWsl() {
127164
+ const status = checkSmartStackInWsl();
127165
+ if (status.installed) return { success: true, version: status.version, skipped: true };
127166
+ const nodeCheck = checkNodeInWsl();
127167
+ if (!nodeCheck.installed) {
127168
+ return { success: false, error: "Node.js is not installed (required for SmartStack CLI)" };
127169
+ }
127170
+ const spinner = logger.spinner("Installing SmartStack CLI...");
127171
+ const result = wslInstall(
127172
+ "source ~/.nvm/nvm.sh && npm install -g @atlashub/smartstack-cli",
127173
+ 18e4
127174
+ );
127175
+ if (result === null) {
127176
+ spinner.fail("Failed to install SmartStack CLI");
127177
+ return { success: false, error: "npm install -g @atlashub/smartstack-cli failed" };
127178
+ }
127179
+ const check = checkSmartStackInWsl();
127180
+ if (check.installed) {
127181
+ spinner.succeed(`SmartStack CLI ${check.version} installed`);
127182
+ return { success: true, version: check.version };
127183
+ }
127184
+ spinner.fail("SmartStack CLI installation could not be verified");
127185
+ return { success: false, error: "Verification failed after install" };
127186
+ }
127187
+ function installStartupScript() {
127188
+ const script = [
127189
+ "#!/bin/bash",
127190
+ "source ~/.nvm/nvm.sh 2>/dev/null",
127191
+ 'export DOTNET_ROOT="$HOME/.dotnet"',
127192
+ 'export PATH="$PATH:$HOME/.dotnet:$HOME/.dotnet/tools"',
127193
+ "",
127194
+ "if tmux has-session -t smartstack 2>/dev/null; then",
127195
+ " tmux attach -t smartstack",
127196
+ "else",
127197
+ " tmux new-session -d -s smartstack -n claude",
127198
+ ' tmux send-keys -t smartstack:claude "claude --dangerously-skip-permissions" Enter',
127199
+ " tmux new-window -t smartstack -n dev",
127200
+ " tmux select-window -t smartstack:claude",
127201
+ " tmux attach -t smartstack",
127202
+ "fi"
127203
+ ].join("\n");
127204
+ const result = wslInstall(
127205
+ `mkdir -p ~/.local/bin && cat > ~/.local/bin/smartstack-dev << 'SCRIPT'
127206
+ ${script}
127207
+ SCRIPT
127208
+ chmod +x ~/.local/bin/smartstack-dev`,
127209
+ 1e4
127210
+ );
127211
+ if (result === null) {
127212
+ return { success: false, error: "Failed to write startup script" };
127213
+ }
127214
+ wslInstall(
127215
+ `grep -q ".local/bin" ~/.bashrc || echo 'export PATH="$PATH:$HOME/.local/bin"' >> ~/.bashrc`,
127216
+ 5e3
127217
+ );
127218
+ return { success: true };
127219
+ }
127109
127220
  var SMARTSTACK_PROFILE_NAME = "SmartStack Dev";
127110
127221
  var SMARTSTACK_PROFILE_GUID = "{17ce5bfe-17ed-5f3a-ab15-5cd5baafed5b}";
127111
127222
  function checkWindowsTerminal() {
@@ -127174,7 +127285,7 @@ function configureWindowsTerminal() {
127174
127285
  const profile = {
127175
127286
  guid: SMARTSTACK_PROFILE_GUID,
127176
127287
  name: SMARTSTACK_PROFILE_NAME,
127177
- commandline: 'wsl -e bash -lc "source ~/.nvm/nvm.sh 2>/dev/null; tmux new-session -A -s smartstack"',
127288
+ commandline: "wsl -e bash -l ~/.local/bin/smartstack-dev",
127178
127289
  icon: "\u26A1",
127179
127290
  colorScheme: "One Half Dark",
127180
127291
  startingDirectory: "~"
@@ -127212,14 +127323,15 @@ var tmuxCommand = new Command("tmux").description("WSL development environment s
127212
127323
  console.log(` ${source_default.cyan("ss tmux install")} Set up complete WSL dev environment`);
127213
127324
  console.log(` ${source_default.cyan("ss tmux status")} Check WSL environment status`);
127214
127325
  console.log();
127215
- console.log("Installs: Windows Terminal, git, tmux, nvm, Node.js, .NET 10, Claude Code");
127216
- console.log("Then launches Windows Terminal with Claude Code in tmux.");
127326
+ console.log("Installs: Windows Terminal, git, tmux, nvm, Node.js, .NET 10,");
127327
+ console.log(" Claude Code, SmartStack CLI");
127328
+ console.log("Then launches Windows Terminal with tmux.");
127217
127329
  console.log();
127218
127330
  });
127219
127331
  tmuxCommand.command("install").description("Install complete WSL dev environment and launch Claude Code").option("-f, --force", "Re-install even if already present").option("-v, --verbose", "Show detailed debug output").option("--no-launch", "Do not launch Windows Terminal after install").action(async (options) => {
127220
127332
  if (options.verbose) logger.setVerbose(true);
127221
127333
  logger.header("WSL Development Environment Setup");
127222
- const totalSteps = 10;
127334
+ const totalSteps = 11;
127223
127335
  logger.step(1, totalSteps, "Windows Terminal...");
127224
127336
  const wtStatus = checkWindowsTerminal();
127225
127337
  if (wtStatus.installed && !options.force) {
@@ -127266,7 +127378,8 @@ tmuxCommand.command("install").description("Install complete WSL dev environment
127266
127378
  { name: "nvm", step: 5, check: checkNvmInWsl, install: installNvmInWsl },
127267
127379
  { name: "Node.js", step: 6, check: checkNodeInWsl, install: installNodeInWsl },
127268
127380
  { name: ".NET SDK 10", step: 7, check: checkDotnetInWsl, install: installDotnetInWsl },
127269
- { name: "Claude Code", step: 8, check: checkClaudeInWsl, install: installClaudeInWsl }
127381
+ { name: "Claude Code", step: 8, check: checkClaudeInWsl, install: installClaudeInWsl },
127382
+ { name: "SmartStack CLI", step: 9, check: checkSmartStackInWsl, install: installSmartStackInWsl }
127270
127383
  ];
127271
127384
  let allSuccess = true;
127272
127385
  const results = [];
@@ -127307,7 +127420,7 @@ tmuxCommand.command("install").description("Install complete WSL dev environment
127307
127420
  ], "error");
127308
127421
  process.exit(1);
127309
127422
  }
127310
- logger.step(9, totalSteps, "Configuring Windows Terminal...");
127423
+ logger.step(10, totalSteps, "Configuring Windows Terminal...");
127311
127424
  const wtCheck = checkWindowsTerminal();
127312
127425
  if (wtCheck.installed) {
127313
127426
  const configResult = configureWindowsTerminal();
@@ -127324,8 +127437,14 @@ tmuxCommand.command("install").description("Install complete WSL dev environment
127324
127437
  } else {
127325
127438
  logger.warning("Windows Terminal not available - skipping configuration");
127326
127439
  }
127440
+ const scriptResult = installStartupScript();
127441
+ if (scriptResult.success) {
127442
+ logger.success("Startup script installed (~/.local/bin/smartstack-dev)");
127443
+ } else {
127444
+ logger.warning(`Startup script: ${scriptResult.error}`);
127445
+ }
127327
127446
  console.log();
127328
- logger.step(10, totalSteps, "Launching...");
127447
+ logger.step(11, totalSteps, "Launching...");
127329
127448
  if (options.launch === false) {
127330
127449
  logger.info("Launch skipped (--no-launch)");
127331
127450
  logger.box([
@@ -127374,6 +127493,7 @@ tmuxCommand.command("status").description("Show WSL development environment stat
127374
127493
  const nodeStatus = checkNodeInWsl();
127375
127494
  const dotnetStatus = checkDotnetInWsl();
127376
127495
  const claudeStatus = checkClaudeInWsl();
127496
+ const smartstackStatus = checkSmartStackInWsl();
127377
127497
  if (options.json) {
127378
127498
  console.log(JSON.stringify({
127379
127499
  wsl: wslStatus,
@@ -127384,10 +127504,11 @@ tmuxCommand.command("status").description("Show WSL development environment stat
127384
127504
  nvm: nvmStatus,
127385
127505
  node: nodeStatus,
127386
127506
  dotnet: dotnetStatus,
127387
- claude: claudeStatus
127507
+ claude: claudeStatus,
127508
+ smartstack: smartstackStatus
127388
127509
  }
127389
127510
  }, null, 2));
127390
- const allInstalled2 = wtStatus.installed && gitStatus.installed && tmuxStatus.installed && nodeStatus.installed && dotnetStatus.installed && claudeStatus.installed;
127511
+ const allInstalled2 = wtStatus.installed && gitStatus.installed && tmuxStatus.installed && nodeStatus.installed && dotnetStatus.installed && claudeStatus.installed && smartstackStatus.installed;
127391
127512
  process.exit(allInstalled2 ? 0 : 1);
127392
127513
  }
127393
127514
  logger.header("WSL Development Environment Status");
@@ -127419,7 +127540,8 @@ tmuxCommand.command("status").description("Show WSL development environment stat
127419
127540
  { name: "nvm", s: nvmStatus },
127420
127541
  { name: "Node.js", s: nodeStatus },
127421
127542
  { name: ".NET SDK", s: dotnetStatus },
127422
- { name: "Claude Code", s: claudeStatus }
127543
+ { name: "Claude Code", s: claudeStatus },
127544
+ { name: "SmartStack CLI", s: smartstackStatus }
127423
127545
  ];
127424
127546
  for (const t of tools) {
127425
127547
  table.push([