@ait-co/console-cli 0.1.17 → 0.1.18

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/cli.mjs CHANGED
@@ -1,13 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import { defineCommand, runMain } from "citty";
3
- import { access, chmod, mkdir, mkdtemp, readFile, rename, rm, unlink, writeFile } from "node:fs/promises";
3
+ import { access, chmod, copyFile, mkdir, mkdtemp, readFile, rename, rm, unlink, writeFile } from "node:fs/promises";
4
4
  import { basename, dirname, isAbsolute, join, resolve, win32 } from "node:path";
5
5
  import { homedir, tmpdir } from "node:os";
6
6
  import { unzipSync } from "fflate";
7
7
  import { parse } from "yaml";
8
8
  import { imageSize } from "image-size";
9
- import { spawn } from "node:child_process";
9
+ import { execFile, spawn } from "node:child_process";
10
10
  import { constants, createReadStream } from "node:fs";
11
+ import { promisify } from "node:util";
11
12
  import { createHash } from "node:crypto";
12
13
  //#region src/api/http.ts
13
14
  var TossApiError = class extends Error {
@@ -720,7 +721,8 @@ const ExitCode = {
720
721
  ApiError: 17,
721
722
  UpgradeUnavailable: 20,
722
723
  UpgradeAlreadyLatest: 21,
723
- UpgradeChecksumFailed: 22
724
+ UpgradeChecksumFailed: 22,
725
+ UpgradeSmokeTestFailed: 23
724
726
  };
725
727
  //#endregion
726
728
  //#region src/flush.ts
@@ -5559,13 +5561,14 @@ function resolveVersion() {
5559
5561
  if (typeof injected === "string" && injected.length > 0) return injected;
5560
5562
  } catch {}
5561
5563
  try {
5562
- return "0.1.17";
5564
+ return "0.1.18";
5563
5565
  } catch {}
5564
5566
  return "0.0.0-dev";
5565
5567
  }
5566
5568
  const VERSION = resolveVersion();
5567
5569
  //#endregion
5568
5570
  //#region src/commands/upgrade.ts
5571
+ const execFileP = promisify(execFile);
5569
5572
  function isStandaloneBinary() {
5570
5573
  return basename(process.execPath).toLowerCase().startsWith("aitcc");
5571
5574
  }
@@ -5724,12 +5727,26 @@ const upgradeCommand = defineCommand({
5724
5727
  process.exit(ExitCode.UpgradeChecksumFailed);
5725
5728
  }
5726
5729
  if (!args.json) process.stdout.write("Checksum OK.\n");
5730
+ const backupPath = process.platform === "win32" ? null : `${exePath}.bak.${Date.now()}`;
5731
+ if (backupPath) try {
5732
+ await copyFile(exePath, backupPath);
5733
+ } catch (err) {
5734
+ await unlink(stagingPath).catch(() => {});
5735
+ emitError({
5736
+ reason: "backup-failed",
5737
+ message: err.message,
5738
+ exePath,
5739
+ backupPath
5740
+ }, `Failed to create rollback backup at ${backupPath}: ${err.message}`);
5741
+ process.exit(ExitCode.Generic);
5742
+ }
5727
5743
  try {
5728
5744
  if (process.platform === "win32") {
5729
5745
  await rename(exePath, `${exePath}.old`);
5730
5746
  await rename(stagingPath, exePath);
5731
5747
  } else await rename(stagingPath, exePath);
5732
5748
  } catch (err) {
5749
+ if (backupPath) await unlink(backupPath).catch(() => {});
5733
5750
  emitError({
5734
5751
  reason: "replace-failed",
5735
5752
  message: err.message,
@@ -5738,6 +5755,45 @@ const upgradeCommand = defineCommand({
5738
5755
  }, `Failed to replace binary at ${exePath}: ${err.message}`);
5739
5756
  process.exit(ExitCode.Generic);
5740
5757
  }
5758
+ let smokeFailure = null;
5759
+ try {
5760
+ const { stdout } = await execFileP(exePath, ["--version"], {
5761
+ timeout: 1e4,
5762
+ windowsHide: true
5763
+ });
5764
+ if (!stdout.trim()) smokeFailure = "empty stdout from --version";
5765
+ } catch (err) {
5766
+ smokeFailure = err.message;
5767
+ }
5768
+ if (smokeFailure) {
5769
+ let rollbackError = null;
5770
+ let recoveryHint = null;
5771
+ try {
5772
+ if (process.platform === "win32") {
5773
+ try {
5774
+ await unlink(exePath);
5775
+ } catch (err) {
5776
+ recoveryHint = `Failed to remove broken binary at ${exePath}; remove it manually then rename ${exePath}.old back to ${exePath}.`;
5777
+ throw err;
5778
+ }
5779
+ await rename(`${exePath}.old`, exePath);
5780
+ } else if (backupPath) await rename(backupPath, exePath);
5781
+ } catch (err) {
5782
+ rollbackError = err.message;
5783
+ if (!recoveryHint) recoveryHint = process.platform === "win32" ? `Rename ${exePath}.old back to ${exePath} to restore the previous binary.` : `Rename ${backupPath} back to ${exePath} to restore the previous binary.`;
5784
+ }
5785
+ emitError({
5786
+ reason: "smoke-test-failed",
5787
+ message: smokeFailure,
5788
+ exePath,
5789
+ ...rollbackError ? {
5790
+ rollbackError,
5791
+ backupPath
5792
+ } : { rolledBack: true }
5793
+ }, rollbackError ? `New binary failed --version smoke test: ${smokeFailure}\nRollback also failed: ${rollbackError}\n${recoveryHint}` : `New binary failed --version smoke test: ${smokeFailure}\nReverted to previous binary.`);
5794
+ process.exit(ExitCode.UpgradeSmokeTestFailed);
5795
+ }
5796
+ if (backupPath) await unlink(backupPath).catch(() => {});
5741
5797
  emit({
5742
5798
  ok: true,
5743
5799
  status: "upgraded",