@tuned-tensor/cli 0.22.0 → 0.22.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/README.md CHANGED
@@ -72,7 +72,7 @@ npm install -g --ignore-scripts @tuned-tensor/cli
72
72
  tt --version
73
73
  ```
74
74
 
75
- Uninstall with `npm uninstall -g @tuned-tensor/cli` (add
75
+ Upgrade later with `tt upgrade`. Uninstall with `npm uninstall -g @tuned-tensor/cli` (add
76
76
  `--prefix ~/.local` if the curl installer used that prefix).
77
77
 
78
78
  Node.js 22.19.0 or newer is required. Training additionally needs
@@ -156,10 +156,19 @@ catalog providers remain available by ID. Unauthenticated entries are marked
156
156
  `auth required`. Local endpoints such as Ollama use a placeholder `apiKey` in
157
157
  `models.json` and need no TT account.
158
158
 
159
- Before the shell opens, `tt` performs a short, non-blocking npm version check.
160
- If a newer stable release is available it recommends
161
- `npm install -g @tuned-tensor/cli@latest`; offline or unavailable registry
162
- checks are ignored.
159
+ `tt` checks npm for a newer stable release at most every 12 hours and
160
+ remembers the answer in `~/.tuned-tensor/update-check.json`. The notice appears
161
+ when the shell opens and after commands run in a terminal; explicit commands
162
+ never wait on the registry. Upgrade with:
163
+
164
+ ```bash
165
+ tt upgrade # latest stable, into the same npm prefix tt runs from
166
+ tt upgrade --check # only report
167
+ tt upgrade beta # or a specific version
168
+ ```
169
+
170
+ Offline or unavailable registry checks are ignored. `CI`, `TT_NO_UPDATE_CHECK=1`
171
+ or `NO_UPDATE_NOTIFIER=1` disable the check.
163
172
 
164
173
  After a model is selected, the banner shows it and ordinary sentences go to
165
174
  the agent:
@@ -7768,6 +7768,7 @@ export {
7768
7768
  DEFAULT_FOUNDATION_RUNS_DIR,
7769
7769
  DEFAULT_DECISION_RUNS_DIR,
7770
7770
  expandUserPath,
7771
+ getTunedTensorHome,
7771
7772
  getConfigDir,
7772
7773
  getAgentConfigDir,
7773
7774
  defaultStoreRoot,
@@ -7896,4 +7897,4 @@ export {
7896
7897
  assessHardware,
7897
7898
  createRunConsoleReporter
7898
7899
  };
7899
- //# sourceMappingURL=chunk-4SUXBHIY.js.map
7900
+ //# sourceMappingURL=chunk-RPWOCVIL.js.map
package/dist/index.js CHANGED
@@ -33,6 +33,7 @@ import {
33
33
  formatHostStatusLine,
34
34
  getAgentConfigDir,
35
35
  getConfigDir,
36
+ getTunedTensorHome,
36
37
  hardenExistingLocalStore,
37
38
  isFoundationPipeline,
38
39
  loadLocalRunInput,
@@ -58,13 +59,13 @@ import {
58
59
  warningsFromSnapshot,
59
60
  withDecisionPythonEnvironment,
60
61
  withFoundationPythonEnvironment
61
- } from "./chunk-4SUXBHIY.js";
62
+ } from "./chunk-RPWOCVIL.js";
62
63
 
63
64
  // src/cli.ts
64
- import { spawn as spawn4 } from "child_process";
65
+ import { spawn as spawn6 } from "child_process";
65
66
  import { constants as osConstants2 } from "os";
66
67
  import { Command } from "commander";
67
- import chalk13 from "chalk";
68
+ import chalk15 from "chalk";
68
69
 
69
70
  // src/local-agent-client.ts
70
71
  import { randomUUID as randomUUID5 } from "crypto";
@@ -4127,6 +4128,7 @@ var COMMAND_CATALOG = [
4127
4128
  { path: "models rollback", description: "Roll back the active local model.", group: "Serving", modes: LOCAL },
4128
4129
  { path: "serve", description: "Serve a local adapter, active model, or base model.", group: "Serving", modes: LOCAL },
4129
4130
  { path: "info", description: "Show local runtime package information.", group: "Inspect", modes: LOCAL },
4131
+ { path: "upgrade", description: "Upgrade tt to the latest release.", group: "Inspect", modes: LOCAL },
4130
4132
  { path: "status", description: "Show local project context.", group: "Inspect", modes: LOCAL },
4131
4133
  { path: "agent models", description: "List provider models for the laptop-local TT agent.", group: "Inspect", modes: LOCAL },
4132
4134
  { path: "agent configure", description: "Select the laptop-local TT agent model.", group: "Inspect", modes: LOCAL },
@@ -12385,8 +12387,20 @@ function registerUsageCommand(parent) {
12385
12387
  });
12386
12388
  }
12387
12389
 
12390
+ // src/commands/upgrade.ts
12391
+ import { spawn as spawn5 } from "child_process";
12392
+ import { accessSync, constants as constants3, existsSync as existsSync10, readFileSync as readFileSync15, realpathSync } from "fs";
12393
+ import { dirname as dirname13, join as join17 } from "path";
12394
+ import chalk14 from "chalk";
12395
+
12388
12396
  // src/update-check.ts
12397
+ import { spawn as spawn4 } from "child_process";
12398
+ import { mkdirSync as mkdirSync5, readFileSync as readFileSync14, writeFileSync as writeFileSync7 } from "fs";
12399
+ import { dirname as dirname12, join as join16 } from "path";
12400
+ import chalk13 from "chalk";
12401
+ var CLI_PACKAGE_NAME = "@tuned-tensor/cli";
12389
12402
  var PACKAGE_LATEST_URL = "https://registry.npmjs.org/@tuned-tensor%2fcli/latest";
12403
+ var DEFAULT_CACHE_MAX_AGE_MS = 12 * 60 * 60 * 1e3;
12390
12404
  function parseVersion(version) {
12391
12405
  const match = version.trim().match(
12392
12406
  /^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/
@@ -12430,11 +12444,50 @@ function compareVersions(left, right) {
12430
12444
  }
12431
12445
  return comparePrerelease(left.prerelease, right.prerelease);
12432
12446
  }
12433
- async function checkForCliUpdate(currentVersion, options = {}) {
12447
+ function getCliUpdateCacheFile(env = process.env) {
12448
+ return join16(getTunedTensorHome(env), "update-check.json");
12449
+ }
12450
+ function cliUpdateChecksDisabled(env = process.env) {
12451
+ return [env.TT_NO_UPDATE_CHECK, env.NO_UPDATE_NOTIFIER, env.CI].some((value) => value !== void 0 && value !== "" && value !== "0" && value !== "false");
12452
+ }
12453
+ function readUpdateCache(file) {
12454
+ try {
12455
+ const payload = JSON.parse(readFileSync14(file, "utf8"));
12456
+ if (typeof payload.checkedAt !== "number" || typeof payload.latestVersion !== "string" || !parseVersion(payload.latestVersion)) return null;
12457
+ return { checkedAt: payload.checkedAt, latestVersion: payload.latestVersion };
12458
+ } catch {
12459
+ return null;
12460
+ }
12461
+ }
12462
+ function writeUpdateCache(file, cache) {
12463
+ try {
12464
+ mkdirSync5(dirname12(file), { recursive: true });
12465
+ writeFileSync7(file, `${JSON.stringify(cache)}
12466
+ `);
12467
+ } catch {
12468
+ }
12469
+ }
12470
+ function recordLatestCliVersion(cacheFile, latestVersion, now = Date.now()) {
12471
+ writeUpdateCache(cacheFile, { checkedAt: now, latestVersion });
12472
+ }
12473
+ function compareCliVersions(left, right) {
12474
+ const parsedLeft = parseVersion(left);
12475
+ const parsedRight = parseVersion(right);
12476
+ if (!parsedLeft || !parsedRight) return null;
12477
+ return compareVersions(parsedLeft, parsedRight);
12478
+ }
12479
+ function newerStableRelease(currentVersion, latestVersion) {
12480
+ if (!latestVersion) return null;
12434
12481
  const current = parseVersion(currentVersion);
12435
- if (!current) return null;
12482
+ const latest = parseVersion(latestVersion);
12483
+ if (!current || !latest || latest.prerelease.length > 0 || compareVersions(latest, current) <= 0) return null;
12484
+ return { currentVersion, latestVersion };
12485
+ }
12486
+ async function fetchLatestCliVersion(options = {}) {
12436
12487
  const controller = new AbortController();
12437
- const timeoutMs = options.timeoutMs ?? 750;
12488
+ const abort = () => controller.abort();
12489
+ options.signal?.addEventListener("abort", abort, { once: true });
12490
+ const timeoutMs = options.timeoutMs ?? 1500;
12438
12491
  let timeout;
12439
12492
  const request2 = (async () => {
12440
12493
  try {
@@ -12446,11 +12499,7 @@ async function checkForCliUpdate(currentVersion, options = {}) {
12446
12499
  const payload = await response.json();
12447
12500
  if (typeof payload.version !== "string") return null;
12448
12501
  const latest = parseVersion(payload.version);
12449
- if (!latest || latest.prerelease.length > 0 || compareVersions(latest, current) <= 0) return null;
12450
- return {
12451
- currentVersion,
12452
- latestVersion: payload.version
12453
- };
12502
+ return latest && latest.prerelease.length === 0 ? payload.version : null;
12454
12503
  } catch {
12455
12504
  return null;
12456
12505
  }
@@ -12465,15 +12514,211 @@ async function checkForCliUpdate(currentVersion, options = {}) {
12465
12514
  return await Promise.race([request2, deadline]);
12466
12515
  } finally {
12467
12516
  if (timeout) clearTimeout(timeout);
12517
+ options.signal?.removeEventListener("abort", abort);
12468
12518
  }
12469
12519
  }
12520
+ function cachedCliUpdate(currentVersion, cacheFile) {
12521
+ return newerStableRelease(currentVersion, readUpdateCache(cacheFile)?.latestVersion);
12522
+ }
12523
+ function cliUpdateCacheIsStale(cacheFile, options = {}) {
12524
+ const cache = readUpdateCache(cacheFile);
12525
+ const now = (options.now ?? Date.now)();
12526
+ return !cache || now - cache.checkedAt >= (options.cacheMaxAgeMs ?? DEFAULT_CACHE_MAX_AGE_MS);
12527
+ }
12528
+ async function refreshCliUpdateCache(cacheFile, options = {}) {
12529
+ const latest = await fetchLatestCliVersion(options);
12530
+ if (latest) recordLatestCliVersion(cacheFile, latest, (options.now ?? Date.now)());
12531
+ return latest;
12532
+ }
12533
+ var REFRESH_SCRIPT = `
12534
+ const [url, file] = process.argv.slice(1);
12535
+ const fs = require("node:fs");
12536
+ const path = require("node:path");
12537
+ fetch(url, { headers: { accept: "application/json" }, signal: AbortSignal.timeout(10000) })
12538
+ .then((response) => response.ok ? response.json() : null)
12539
+ .then((payload) => {
12540
+ if (!payload || typeof payload.version !== "string") return;
12541
+ fs.mkdirSync(path.dirname(file), { recursive: true });
12542
+ fs.writeFileSync(file, JSON.stringify({ checkedAt: Date.now(), latestVersion: payload.version }) + "\\n");
12543
+ })
12544
+ .catch(() => {});
12545
+ `;
12546
+ function spawnCliUpdateRefresh(cacheFile) {
12547
+ const cached = readUpdateCache(cacheFile);
12548
+ if (cached) recordLatestCliVersion(cacheFile, cached.latestVersion);
12549
+ try {
12550
+ const child = spawn4(
12551
+ process.execPath,
12552
+ ["-e", REFRESH_SCRIPT, PACKAGE_LATEST_URL, cacheFile],
12553
+ { detached: true, stdio: "ignore", windowsHide: true }
12554
+ );
12555
+ child.on("error", () => {
12556
+ });
12557
+ child.unref();
12558
+ } catch {
12559
+ }
12560
+ }
12561
+ async function checkForCliUpdate(currentVersion, options = {}) {
12562
+ if (!parseVersion(currentVersion)) return null;
12563
+ const { cacheFile } = options;
12564
+ if (cacheFile && !cliUpdateCacheIsStale(cacheFile, options)) {
12565
+ return cachedCliUpdate(currentVersion, cacheFile);
12566
+ }
12567
+ const latest = cacheFile ? await refreshCliUpdateCache(cacheFile, options) : await fetchLatestCliVersion(options);
12568
+ return newerStableRelease(
12569
+ currentVersion,
12570
+ latest ?? (cacheFile ? readUpdateCache(cacheFile)?.latestVersion : void 0)
12571
+ );
12572
+ }
12470
12573
  function formatCliUpdateNotice(update) {
12471
12574
  return [
12472
- `Update available: tt ${update.currentVersion} \u2192 ${update.latestVersion}`,
12473
- "Upgrade with: npm install -g @tuned-tensor/cli@latest"
12575
+ chalk13.yellow(`Update available: tt ${update.currentVersion} \u2192 ${chalk13.bold(update.latestVersion)}`),
12576
+ `Run ${chalk13.bold("tt upgrade")} to install it.`
12474
12577
  ].join("\n");
12475
12578
  }
12476
12579
 
12580
+ // src/commands/upgrade.ts
12581
+ function resolveGlobalInstall(entrypoint, platform = process.platform) {
12582
+ if (!entrypoint) return null;
12583
+ let script;
12584
+ try {
12585
+ script = realpathSync(entrypoint);
12586
+ } catch {
12587
+ return null;
12588
+ }
12589
+ if (/[\\/]_npx[\\/]/.test(script)) return null;
12590
+ const match = platform === "win32" ? script.match(/^(.*)\\node_modules\\@tuned-tensor\\cli\\dist\\index\.js$/i) : script.match(/^(.*)\/lib\/node_modules\/@tuned-tensor\/cli\/dist\/index\.js$/);
12591
+ if (!match?.[1]) return null;
12592
+ return { prefix: match[1], packageDir: dirname13(dirname13(script)) };
12593
+ }
12594
+ function prefixIsWritable(prefix, platform) {
12595
+ const modules = platform === "win32" ? join17(prefix, "node_modules") : join17(prefix, "lib", "node_modules");
12596
+ try {
12597
+ accessSync(existsSync10(modules) ? modules : prefix, constants3.W_OK);
12598
+ return true;
12599
+ } catch {
12600
+ return false;
12601
+ }
12602
+ }
12603
+ function installedVersion(packageDir) {
12604
+ try {
12605
+ const manifest = JSON.parse(readFileSync15(join17(packageDir, "package.json"), "utf8"));
12606
+ return typeof manifest.version === "string" ? manifest.version : void 0;
12607
+ } catch {
12608
+ return void 0;
12609
+ }
12610
+ }
12611
+ function quoteForCmd(arg) {
12612
+ return /[\s"&|<>^]/.test(arg) ? `"${arg.replace(/"/g, '""')}"` : arg;
12613
+ }
12614
+ function defaultNpmRunner(platform) {
12615
+ return async (args2) => await new Promise((resolve13, reject) => {
12616
+ const windows = platform === "win32";
12617
+ const child = spawn5(
12618
+ windows ? "npm.cmd" : "npm",
12619
+ windows ? args2.map(quoteForCmd) : args2,
12620
+ {
12621
+ shell: windows,
12622
+ // Keep stdout clean for --json; npm progress goes to stderr.
12623
+ stdio: ["ignore", isJsonMode() ? 2 : "inherit", "inherit"]
12624
+ }
12625
+ );
12626
+ child.once("error", reject);
12627
+ child.once("close", (code2) => resolve13(code2 ?? 1));
12628
+ });
12629
+ }
12630
+ function formatCommand(args2) {
12631
+ return ["npm", ...args2].map((arg) => /\s/.test(arg) ? JSON.stringify(arg) : arg).join(" ");
12632
+ }
12633
+ function registerUpgradeCommand(program, deps) {
12634
+ program.command("upgrade").alias("update").description("Upgrade tt to the latest release").argument("[version]", "Version or npm dist-tag to install (default: latest)").option("--check", "Only report whether an update is available").addHelpText(
12635
+ "after",
12636
+ `
12637
+ Examples:
12638
+ tt upgrade Install the latest stable release
12639
+ tt upgrade --check Report whether a newer release exists
12640
+ tt upgrade beta Opt in to the beta channel
12641
+ tt upgrade 0.21.0 Install a specific version
12642
+
12643
+ Set TT_NO_UPDATE_CHECK=1 to silence update notices.
12644
+ `
12645
+ ).action(async (requested, options) => {
12646
+ const platform = deps.platform ?? process.platform;
12647
+ const cacheFile = getCliUpdateCacheFile(deps.env);
12648
+ const current = deps.version;
12649
+ const target = requested?.trim() || "latest";
12650
+ let latest;
12651
+ if (target === "latest") {
12652
+ latest = await fetchLatestCliVersion({ fetchImpl: deps.fetchImpl, timeoutMs: 1e4 }) ?? void 0;
12653
+ if (!latest) {
12654
+ throw new Error(
12655
+ "Could not reach the npm registry to look up the latest tt release. Check your connection and try again."
12656
+ );
12657
+ }
12658
+ recordLatestCliVersion(cacheFile, latest);
12659
+ const comparison = compareCliVersions(latest, current);
12660
+ if (comparison !== null && comparison <= 0) {
12661
+ if (isJsonMode()) {
12662
+ printJson({ current_version: current, latest_version: latest, update_available: false });
12663
+ } else {
12664
+ printSuccess(`tt ${current} is the latest version.`);
12665
+ }
12666
+ return;
12667
+ }
12668
+ }
12669
+ if (options.check) {
12670
+ if (isJsonMode()) {
12671
+ printJson({ current_version: current, latest_version: latest ?? null, update_available: Boolean(latest) });
12672
+ } else if (latest) {
12673
+ console.log(`Update available: tt ${current} \u2192 ${chalk14.bold(latest)}`);
12674
+ console.log(`Run ${chalk14.bold("tt upgrade")} to install it.`);
12675
+ } else {
12676
+ console.log(`tt ${current} is installed. Run ${chalk14.bold(`tt upgrade ${target}`)} to install ${target}.`);
12677
+ }
12678
+ return;
12679
+ }
12680
+ const install = resolveGlobalInstall(deps.entrypoint, platform);
12681
+ const packageSpec = `${CLI_PACKAGE_NAME}@${target}`;
12682
+ if (!install) {
12683
+ throw new Error(
12684
+ `This tt (${deps.entrypoint ?? "unknown path"}) was not installed with npm -g, so it can't upgrade itself.
12685
+ Upgrade it the way you installed it, for example:
12686
+ npm install -g --ignore-scripts ${packageSpec}`
12687
+ );
12688
+ }
12689
+ const npmArgs = ["install", "-g", "--ignore-scripts", "--prefix", install.prefix, packageSpec];
12690
+ if (!prefixIsWritable(install.prefix, platform)) {
12691
+ throw new Error(
12692
+ `tt is installed in ${install.prefix}, which this user can't write to. Run:
12693
+ sudo ${formatCommand(npmArgs)}`
12694
+ );
12695
+ }
12696
+ if (!isJsonMode()) {
12697
+ console.log(`Upgrading tt ${current} \u2192 ${chalk14.bold(latest ?? target)}`);
12698
+ console.log(chalk14.dim(`$ ${formatCommand(npmArgs)}`));
12699
+ }
12700
+ let code2;
12701
+ try {
12702
+ code2 = await (deps.runNpm ?? defaultNpmRunner(platform))(npmArgs);
12703
+ } catch (error) {
12704
+ throw new Error(
12705
+ `Could not run npm (${error instanceof Error ? error.message : String(error)}). Run it yourself:
12706
+ ${formatCommand(npmArgs)}`
12707
+ );
12708
+ }
12709
+ if (code2 !== 0) {
12710
+ throw new Error(`npm exited with code ${code2}. Run it yourself to see details:
12711
+ ${formatCommand(npmArgs)}`);
12712
+ }
12713
+ const installed = installedVersion(install.packageDir) ?? latest ?? target;
12714
+ if (isJsonMode()) {
12715
+ printJson({ previous_version: current, version: installed, prefix: install.prefix });
12716
+ } else {
12717
+ printSuccess(`Upgraded tt ${current} \u2192 ${installed}. Restart any open tt sessions to use it.`);
12718
+ }
12719
+ });
12720
+ }
12721
+
12477
12722
  // src/cli.ts
12478
12723
  function createAccountToolApi(opts) {
12479
12724
  return {
@@ -12584,7 +12829,7 @@ async function runSelfCommand(args2, options = {}) {
12584
12829
  throw new Error("Cannot locate the tt CLI entrypoint.");
12585
12830
  }
12586
12831
  return await new Promise((resolve13, reject) => {
12587
- const child = spawn4(process.execPath, [entrypoint, ...args2], {
12832
+ const child = spawn6(process.execPath, [entrypoint, ...args2], {
12588
12833
  cwd: options.cwd,
12589
12834
  env: options.env ?? process.env,
12590
12835
  stdio: "inherit",
@@ -12686,7 +12931,7 @@ function createProgram(version, runtime = {}) {
12686
12931
  if (root.json) setJsonMode(true);
12687
12932
  if (root.color === false) {
12688
12933
  process.env.FORCE_COLOR = "0";
12689
- chalk13.level = 0;
12934
+ chalk15.level = 0;
12690
12935
  }
12691
12936
  });
12692
12937
  registerLocalCommands(program, {
@@ -12705,6 +12950,11 @@ function createProgram(version, runtime = {}) {
12705
12950
  registerUsageCommand(program);
12706
12951
  registerPublishCommand(program);
12707
12952
  registerCloudCommands(program);
12953
+ registerUpgradeCommand(program, {
12954
+ version,
12955
+ entrypoint: runtime.argv?.[1] ?? process.argv[1],
12956
+ env
12957
+ });
12708
12958
  registerAgentCommands(program, {
12709
12959
  get env() {
12710
12960
  return childEnvironment2(program.opts(), env);
@@ -12724,12 +12974,12 @@ function createProgram(version, runtime = {}) {
12724
12974
  `);
12725
12975
  return;
12726
12976
  }
12727
- output.write(`${chalk13.bold.hex("#8B5CF6")("Tuned Tensor status")}
12977
+ output.write(`${chalk15.bold.hex("#8B5CF6")("Tuned Tensor status")}
12728
12978
  `);
12729
12979
  output.write(`${formatShellStatus(context).join("\n")}
12730
12980
 
12731
12981
  `);
12732
- output.write(`${chalk13.bold("Context")}
12982
+ output.write(`${chalk15.bold("Context")}
12733
12983
  `);
12734
12984
  output.write(`${formatShellContext(context).join("\n")}
12735
12985
  `);
@@ -12785,7 +13035,11 @@ async function runCli(version, runtime = {}) {
12785
13035
  const error = runtime.stderr ?? process.stderr;
12786
13036
  let update = null;
12787
13037
  try {
12788
- update = await (runtime.checkForUpdate ?? checkForCliUpdate)(version);
13038
+ if (runtime.checkForUpdate) {
13039
+ update = await runtime.checkForUpdate(version);
13040
+ } else if (!cliUpdateChecksDisabled(env)) {
13041
+ update = await checkForCliUpdate(version, { cacheFile: getCliUpdateCacheFile(env) });
13042
+ }
12789
13043
  } catch {
12790
13044
  }
12791
13045
  if (update) {
@@ -12826,11 +13080,29 @@ async function runCli(version, runtime = {}) {
12826
13080
  return;
12827
13081
  }
12828
13082
  if (argv.includes("--json")) setJsonMode(true);
12829
- await createProgram(version, { ...runtime, argv }).parseAsync(argv);
13083
+ const notifier = startCommandUpdateNotifier(version, args2, runtime, env);
13084
+ try {
13085
+ await createProgram(version, { ...runtime, argv }).parseAsync(argv);
13086
+ } finally {
13087
+ notifier?.();
13088
+ }
13089
+ }
13090
+ function startCommandUpdateNotifier(version, args2, runtime, env) {
13091
+ const error = runtime.stderr ?? process.stderr;
13092
+ if (runtime.checkForUpdate || error.isTTY !== true || cliUpdateChecksDisabled(env) || args2.some((arg) => ["--json", "--version", "-V", "--help", "-h"].includes(arg)) || ["upgrade", "update", "help"].includes(args2[0] ?? "")) return null;
13093
+ const cacheFile = getCliUpdateCacheFile(env);
13094
+ if (cliUpdateCacheIsStale(cacheFile)) spawnCliUpdateRefresh(cacheFile);
13095
+ return () => {
13096
+ if (isJsonMode()) return;
13097
+ const update = cachedCliUpdate(version, cacheFile);
13098
+ if (update) error.write(`
13099
+ ${formatCliUpdateNotice(update)}
13100
+ `);
13101
+ };
12830
13102
  }
12831
13103
 
12832
13104
  // src/index.ts
12833
- runCli("0.22.0").catch((err) => {
13105
+ runCli("0.22.1").catch((err) => {
12834
13106
  reportError(err);
12835
13107
  process.exit(1);
12836
13108
  });