@nmakarov/cli-toolkit 0.46.0 → 0.49.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
@@ -1388,36 +1388,29 @@ var Args = class _Args {
1388
1388
  }
1389
1389
  return;
1390
1390
  }
1391
- let dotEnvPathFile = null;
1392
- const envSpecificFile = `.env.${this.env}`;
1393
- const envSpecificPath = resolve(dotEnvPath, envSpecificFile);
1394
- if (existsSync(envSpecificPath)) {
1395
- dotEnvPathFile = envSpecificPath;
1396
- }
1397
- if (!dotEnvPathFile && !this.get("dotEnvPath")) {
1391
+ let dotEnvPathFile = resolve(dotEnvPath, dotEnvFile);
1392
+ if (!existsSync(dotEnvPathFile) && !this.get("dotEnvPath")) {
1398
1393
  const examplesPath = resolve(dotEnvPath, "examples");
1399
- const examplesEnvSpecificPath = resolve(examplesPath, envSpecificFile);
1400
- if (existsSync(examplesEnvSpecificPath)) {
1401
- dotEnvPathFile = examplesEnvSpecificPath;
1402
- }
1403
- }
1404
- if (!dotEnvPathFile) {
1405
- dotEnvPathFile = resolve(dotEnvPath, dotEnvFile);
1406
- if (!existsSync(dotEnvPathFile)) {
1407
- if (!this.get("dotEnvPath")) {
1408
- const examplesPath = resolve(dotEnvPath, "examples");
1409
- const examplesEnvFile = resolve(examplesPath, dotEnvFile);
1410
- if (existsSync(examplesEnvFile)) {
1411
- dotEnvPathFile = examplesEnvFile;
1412
- } else {
1413
- dotEnvPathFile = resolve(dotEnvPath, "..", dotEnvFile);
1414
- }
1415
- }
1394
+ const examplesEnvFile = resolve(examplesPath, dotEnvFile);
1395
+ if (existsSync(examplesEnvFile)) {
1396
+ dotEnvPathFile = examplesEnvFile;
1397
+ } else {
1398
+ dotEnvPathFile = resolve(dotEnvPath, "..", dotEnvFile);
1416
1399
  }
1417
1400
  }
1418
1401
  if (dotEnvPathFile && existsSync(dotEnvPathFile)) {
1419
1402
  config({ path: dotEnvPathFile, quiet: true });
1420
1403
  }
1404
+ const envSpecificFile = `.env.${this.env}`;
1405
+ const envSpecificPath = resolve(dotEnvPath, envSpecificFile);
1406
+ if (existsSync(envSpecificPath) && envSpecificPath !== dotEnvPathFile) {
1407
+ config({ path: envSpecificPath, quiet: true });
1408
+ } else if (!this.get("dotEnvPath")) {
1409
+ const examplesOverlay = resolve(dotEnvPath, "examples", envSpecificFile);
1410
+ if (existsSync(examplesOverlay)) {
1411
+ config({ path: examplesOverlay, quiet: true });
1412
+ }
1413
+ }
1421
1414
  }
1422
1415
  /**
1423
1416
  * Load configuration files
@@ -5800,10 +5793,9 @@ function buildEcosystemConfig(service, paths) {
5800
5793
  const outLog = join9(paths.logs, `${pm2.appName}.out.log`);
5801
5794
  const errLog = join9(paths.logs, `${pm2.appName}.err.log`);
5802
5795
  return `/**
5803
- * pm2 ecosystem for ${service.name} \u2014 seeded by cli-toolkit deploy (init).
5804
- *
5805
- * cwd points at the \`current\` symlink (created on first deploy).
5806
- * Tweak \`args\` here, then: pm2 reload ${paths.ecosystem} --update-env
5796
+ * pm2 ecosystem for ${service.name} \u2014 written by cli-toolkit deploy from the
5797
+ * service manifest (init/deploy). Do not hand-edit; change pm2.* in the
5798
+ * manifest and redeploy. cwd \u2192 \`current\` symlink.
5807
5799
  */
5808
5800
  module.exports = {
5809
5801
  apps: [
@@ -5811,7 +5803,7 @@ module.exports = {
5811
5803
  name: "${pm2.appName}",
5812
5804
  script: "${pm2.script}",
5813
5805
  cwd: "${paths.current}",
5814
- args: "${pm2.args}",
5806
+ args: "${pm2.args ?? ""}",
5815
5807
  instances: 1,
5816
5808
  exec_mode: "fork",
5817
5809
  autorestart: true,
@@ -5824,6 +5816,8 @@ module.exports = {
5824
5816
  merge_logs: true,
5825
5817
  time: true,
5826
5818
  env: {
5819
+ // cli-toolkit Args: ENV selects env-suffixed defaults (DB_NAME_PRODUCTION, BUCKET_PRODUCTION, \u2026)
5820
+ ENV: "production",
5827
5821
  NODE_ENV: "production",
5828
5822
  },
5829
5823
  },
@@ -5848,17 +5842,17 @@ async function initServiceStructure(service, options = {}) {
5848
5842
  if (!dryRun) await mkdir6(dir, { recursive: true });
5849
5843
  created.push(dir);
5850
5844
  }
5851
- let ecosystemCreated = false;
5852
- if (await pathExists4(paths.ecosystem)) {
5853
- skipped.push(paths.ecosystem);
5845
+ const ecosystemExisted = await pathExists4(paths.ecosystem);
5846
+ if (!dryRun) {
5847
+ await writeFile5(paths.ecosystem, buildEcosystemConfig(service, paths), { mode: 420 });
5848
+ }
5849
+ if (ecosystemExisted) {
5850
+ logger.info(`synced ${paths.ecosystem} from manifest`);
5854
5851
  } else {
5855
- if (!dryRun) {
5856
- await writeFile5(paths.ecosystem, buildEcosystemConfig(service, paths), { mode: 420 });
5857
- }
5858
- ecosystemCreated = true;
5859
5852
  created.push(paths.ecosystem);
5853
+ logger.info(`seeded ${paths.ecosystem}`);
5860
5854
  }
5861
- const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] init-structure service=${service.name} dryRun=${dryRun} created=${created.length} skipped=${skipped.length}
5855
+ const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] init-structure service=${service.name} dryRun=${dryRun} created=${created.length} skipped=${skipped.length} ecosystem=synced
5862
5856
  `;
5863
5857
  if (!dryRun) {
5864
5858
  await mkdir6(paths.logs, { recursive: true });
@@ -5867,8 +5861,7 @@ async function initServiceStructure(service, options = {}) {
5867
5861
  logger.info(`service=${service.name} appsRoot=${paths.root}`);
5868
5862
  logger.info(`created: ${created.length ? created.join(", ") : "(none)"}`);
5869
5863
  logger.info(`already present: ${skipped.length ? skipped.join(", ") : "(none)"}`);
5870
- if (ecosystemCreated) logger.info(`seeded ${paths.ecosystem}`);
5871
- return { paths, created, skipped, ecosystemCreated };
5864
+ return { paths, created, skipped, ecosystemCreated: !ecosystemExisted, ecosystemSynced: true };
5872
5865
  }
5873
5866
 
5874
5867
  // src/deploy/bootstrap-host.js
@@ -5965,11 +5958,55 @@ async function installLogrotate(service, options = {}) {
5965
5958
  await runShell(`sudo cp '${tmp}' '${conf}'`, { logger });
5966
5959
  logger.info(`logrotate config written: ${conf}`);
5967
5960
  }
5961
+ var OPERATOR_SHELL_BEGIN = "# >>> mlsfarm-operator >>>";
5962
+ var OPERATOR_SHELL_END = "# <<< mlsfarm-operator <<<";
5963
+ async function installOperatorShell(service, options = {}) {
5964
+ const { user = "ubuntu", dryRun = false, logger = console } = options;
5965
+ const appsRoot = service.appsRoot;
5966
+ if (!appsRoot) {
5967
+ logger.warn("installOperatorShell: service.appsRoot missing \u2014 skipped");
5968
+ return;
5969
+ }
5970
+ const home = user === "ubuntu" || user === process.env.USER ? join10(homedir(), ".bashrc") : `/home/${user}/.bashrc`;
5971
+ const currentDir = join10(appsRoot, "current");
5972
+ const block = [
5973
+ OPERATOR_SHELL_BEGIN,
5974
+ "# Managed by cli-toolkit deploy bootstrap \u2014 do not edit by hand.",
5975
+ "export ENV=production",
5976
+ `if [ -d "${currentDir}" ]; then`,
5977
+ ` cd "${currentDir}" || true`,
5978
+ "fi",
5979
+ OPERATOR_SHELL_END,
5980
+ ""
5981
+ ].join("\n");
5982
+ if (dryRun) {
5983
+ logger.info(`[dryRun] would update ${home} (ENV=production, cd ${currentDir})`);
5984
+ return;
5985
+ }
5986
+ let existing = "";
5987
+ if (await pathExists5(home)) {
5988
+ existing = await readFile4(home, "utf8");
5989
+ }
5990
+ const begin = existing.indexOf(OPERATOR_SHELL_BEGIN);
5991
+ const end = existing.indexOf(OPERATOR_SHELL_END);
5992
+ let next;
5993
+ if (begin !== -1 && end !== -1 && end > begin) {
5994
+ const afterEnd = end + OPERATOR_SHELL_END.length;
5995
+ const rest = existing.slice(afterEnd).replace(/^\n/, "");
5996
+ next = `${existing.slice(0, begin).replace(/\s*$/, "\n")}${block}${rest}`;
5997
+ } else {
5998
+ next = `${existing.replace(/\s*$/, "\n")}
5999
+ ${block}`;
6000
+ }
6001
+ await writeFile6(home, next, { mode: 420 });
6002
+ logger.info(`operator shell: ${home} \u2192 ENV=production, cd ${currentDir}`);
6003
+ }
5968
6004
  async function bootstrapHost(service, options = {}) {
5969
6005
  const { deployKey = service.deployKey, user = "ubuntu", dryRun = false, logger = console } = options;
5970
6006
  await ensurePm2Startup({ user, dryRun, logger });
5971
6007
  if (deployKey) await installDeployKey(deployKey, { dryRun, logger });
5972
6008
  await installLogrotate(service, { dryRun, logger });
6009
+ await installOperatorShell(service, { user, dryRun, logger });
5973
6010
  logger.info("bootstrap-host complete");
5974
6011
  }
5975
6012
 
@@ -8707,6 +8744,7 @@ export {
8707
8744
  createElement2 as h,
8708
8745
  initServiceStructure,
8709
8746
  installDeps,
8747
+ installOperatorShell,
8710
8748
  ipcFileLogsTableNameForSourceResource,
8711
8749
  joiEdateType,
8712
8750
  joiStringArrayType,