cxstatusline 0.9.1 → 0.10.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
@@ -31,7 +31,7 @@
31
31
  - [🚀 Install](#-install)
32
32
  - [🎛️ Configure](#️-configure)
33
33
  - [🧩 Widgets Catalog](#widgets)
34
- - [🔄 Update & Revert](#update)
34
+ - [🔄 Update, Upgrade & Revert](#update)
35
35
  - [🔍 How it Works](#-how-it-works)
36
36
  - [🏷️ Supported Versions](#supported-versions)
37
37
  - [🩺 Troubleshooting](#-troubleshooting)
@@ -81,7 +81,7 @@ cxstatusline doctor
81
81
 
82
82
  `cxstatusline install` downloads the verified prebuilt binary matching your Codex version, verifies checksums against `manifest.json`, and activates it.
83
83
  - **Interactive selection**: Running `cxstatusline install` opens a keyboard-driven version picker. Use ↑/↓ and Enter to select, or Escape/Ctrl+C to cancel. Prebuilt availability is shown per version; source-only choices require confirmation (unless you already passed `--compile`).
84
- - **Update choices**: `cxstatusline update` uses the same keyboard controls to choose the latest supported prebuilt, a supported source build, or cancellation. It does not update upstream Codex first.
84
+ - **Upgrade choices**: `cxstatusline upgrade` uses the same keyboard controls to choose the latest supported prebuilt, a supported source build, or cancellation. It does not update upstream Codex first.
85
85
  - **Live progress**: Ink renders download progress in terminals while completed stages remain in the transcript. Source builds report their phases; redirected output retains plain milestone logs.
86
86
  - **Target a specific version**: `cxstatusline install --codex-version <version>` (e.g. `cxstatusline install --codex-version 0.154.0`).
87
87
  - **Non-interactive / CI**: Pass `-y` or `--yes` to accept the default without prompting.
@@ -147,19 +147,35 @@ Type IDs match ccstatusline's, so a ccstatusline preset imports without translat
147
147
  👉 The full catalog, and how Custom Command handles timeouts, colours and background caching, are in
148
148
  the **[Usage guide](docs/usage.md)**.
149
149
 
150
- ## Update
150
+ ## Update & Upgrade
151
+
152
+ cxstatusline follows the Homebrew paradigm for managing updates:
153
+ - **`cxstatusline update`**: Updates the **cxstatusline CLI tool itself** to the latest release (via npm, bun, or git).
154
+ - **`cxstatusline upgrade`**: Upgrades the **patched Codex binary pair** to the latest supported release.
155
+
156
+ ### Updating cxstatusline (The Tool)
157
+
158
+ ```sh
159
+ cxstatusline update # Updates cxstatusline to the latest version
160
+ cxstatusline update --check # Checks for available tool updates without installing
161
+ ```
162
+
163
+ `cxstatusline update` automatically detects your install method (`npm`, `bun`, or `git checkout`) and updates the CLI tool.
164
+
165
+ ### Upgrading Patched Codex
151
166
 
152
167
  ```sh
153
- cxstatusline update
168
+ cxstatusline upgrade
154
169
  ```
155
170
 
156
- `cxstatusline update` downloads and verifies the latest published prebuilt supported by your cxstatusline package, then activates the complete patched Codex pair. It does not run Codex's self-updater or modify your original Codex installation. Open a new Codex session afterward.
171
+ `cxstatusline upgrade` downloads and verifies the latest published prebuilt supported by your cxstatusline package, then activates the complete patched Codex pair. It does not run Codex's self-updater or modify your original Codex installation. Open a new Codex session afterward.
157
172
 
158
- The same Codex version is checked for rebuilt patch assets; a newer installed version is never downgraded. If discovery or verification fails, the active pair stays in place. Update the cxstatusline npm package to pick up support for newer Codex versions.
173
+ The same Codex version is checked for rebuilt patch assets; a newer installed version is never downgraded. If discovery or verification fails, the active pair stays in place. When running `upgrade`, if a newer version of `cxstatusline` is available, it will display a friendly reminder to run `cxstatusline update` first.
159
174
 
160
175
  Options:
161
- - `cxstatusline update --compile`: builds the latest locally supported Codex patch from source instead.
176
+ - `cxstatusline upgrade --compile`: builds the latest locally supported Codex patch from source instead.
162
177
  - `--force`, `-y`, and `--yes` remain accepted for compatibility; updates already run without a prompt and always verify the pair.
178
+ - Note: Running `cxstatusline update --compile` or `--force` will automatically forward to `cxstatusline upgrade` with a notice.
163
179
 
164
180
  Session-start updates also leave a newer patched pair in place when the original Codex installation is older, including under the `every` policy.
165
181
 
@@ -59007,8 +59007,8 @@ function runRefreshCommand(cacheKey2, deps) {
59007
59007
  return 0;
59008
59008
  }
59009
59009
  // src/version-info.ts
59010
- var VERSION = "0.9.1";
59011
- var SOURCE_COMMIT = /^[0-9a-f]{40}$/.test("be615bc225cb654e68b5e29a312762d0572f1281") ? "be615bc225cb654e68b5e29a312762d0572f1281" : null;
59010
+ var VERSION = "0.10.1";
59011
+ var SOURCE_COMMIT = /^[0-9a-f]{40}$/.test("cb2f6799d53ce95398331bae1cea4f96d2c9641e") ? "cb2f6799d53ce95398331bae1cea4f96d2c9641e" : null;
59012
59012
  var SOURCE_DIRTY = false;
59013
59013
 
59014
59014
  // src/context.ts
@@ -59149,7 +59149,7 @@ function realContext(env3, io) {
59149
59149
  }
59150
59150
 
59151
59151
  // src/patch/run.ts
59152
- import { appendFileSync, mkdirSync as mkdirSync8 } from "node:fs";
59152
+ import { appendFileSync, mkdirSync as mkdirSync8, rmSync as rmSync6 } from "node:fs";
59153
59153
  import { join as join18 } from "node:path";
59154
59154
 
59155
59155
  // src/lock.ts
@@ -63147,7 +63147,7 @@ function unchangedPair(ctx, manifest, artifact, tag) {
63147
63147
  if (!release || release.tag !== tag || release.archiveSha256 !== artifact.sha256)
63148
63148
  return null;
63149
63149
  const installed = release.manifest;
63150
- const identical = record2.codexVersion === manifest.codexVersion && record2.provenance.cxVersion === manifest.cxVersion && record2.provenance.platform === artifact.platform && record2.provenance.patchVersion === manifest.patchVersion && record2.provenance.patchSha256 === manifest.patchSha256 && record2.provenance.upstreamCommit === manifest.upstreamCommit && installed.cxVersion === manifest.cxVersion && installed.codexVersion === manifest.codexVersion && installed.patchSha256 === manifest.patchSha256 && installed.upstreamCommit === manifest.upstreamCommit;
63150
+ const identical = record2.codexVersion === manifest.codexVersion && (manifest.cxVersion === undefined || record2.provenance.cxVersion === manifest.cxVersion) && record2.provenance.platform === artifact.platform && record2.provenance.patchVersion === manifest.patchVersion && record2.provenance.patchSha256 === manifest.patchSha256 && record2.provenance.upstreamCommit === manifest.upstreamCommit && (manifest.cxVersion === undefined || installed.cxVersion === manifest.cxVersion) && installed.codexVersion === manifest.codexVersion && installed.patchSha256 === manifest.patchSha256 && installed.upstreamCommit === manifest.upstreamCommit;
63151
63151
  if (!identical)
63152
63152
  return null;
63153
63153
  const directory = activeGeneration(ctx.paths);
@@ -64202,7 +64202,7 @@ function wrapperScript(patchedBin, cxBin) {
64202
64202
  WRAPPER_MARKER,
64203
64203
  "# Managed by cxstatusline. `cxstatusline revert` restores stock Codex.",
64204
64204
  `if [ "$1" = "update" ]; then`,
64205
- ` exec ${sq(cxBin)} update`,
64205
+ ` exec ${sq(cxBin)} upgrade`,
64206
64206
  "fi",
64207
64207
  `CXSTATUSLINE_COMMAND=${sq(`${sq(cxBin)} render`)}`,
64208
64208
  "export CXSTATUSLINE_COMMAND",
@@ -64217,7 +64217,7 @@ function generationWrapperScript(currentGeneration, cxBin) {
64217
64217
  WRAPPER_MARKER_V2,
64218
64218
  "# Managed by cxstatusline. `cxstatusline revert` restores stock Codex.",
64219
64219
  `if [ "$1" = "update" ]; then`,
64220
- ` exec ${sq(cxBin)} update`,
64220
+ ` exec ${sq(cxBin)} upgrade`,
64221
64221
  "fi",
64222
64222
  `CXSTATUSLINE_COMMAND=${sq(`${sq(cxBin)} render`)}`,
64223
64223
  "export CXSTATUSLINE_COMMAND",
@@ -65006,11 +65006,37 @@ async function runUpdate(ctx, opts = {}, transport = {}) {
65006
65006
  }
65007
65007
  const installed = readInstallation(ctx.paths)?.codexVersion ?? loadState(ctx).patched_from;
65008
65008
  const current = installed ? parseSemver(installed) : null;
65009
- if (current && compareSemver(current, parseSemver(target)) > 0) {
65009
+ const targetSemver = parseSemver(target);
65010
+ if (current && compareSemver(current, targetSemver) > 0) {
65010
65011
  ctx.say(`Installed Codex ${installed} is newer than the latest supported ${opts.compile ? "patch" : "prebuilt"} (${target}); leaving it unchanged.`);
65011
65012
  return 0;
65012
65013
  }
65013
- if (opts.isTTY && !opts.force && !opts.compile) {
65014
+ if (current && compareSemver(current, targetSemver) === 0 && !opts.force) {
65015
+ const record2 = readInstallation(ctx.paths);
65016
+ if (!opts.compile && record2 && record2.provenance.source === "prebuilt") {
65017
+ try {
65018
+ const expected = {
65019
+ codexVersion: target,
65020
+ platform: platformFor(process.platform, process.arch)
65021
+ };
65022
+ const prepared = await preparePrebuilt(ctx, expected, transport);
65023
+ if (prepared.kind === "unchanged") {
65024
+ ctx.say(`Codex is already up to date (${installed}).`);
65025
+ return 0;
65026
+ }
65027
+ rmSync6(prepared.pair.directory, { recursive: true, force: true });
65028
+ } catch {}
65029
+ } else if (opts.compile && record2 && record2.provenance.source === "compiled") {
65030
+ const patchRef = resolvePatch(manifest, targetSemver);
65031
+ const currentPatch = record2.provenance.patchVersion ?? 1;
65032
+ const targetPatch = patchRef?.patchVersion ?? 1;
65033
+ if (currentPatch >= targetPatch) {
65034
+ ctx.say(`Codex is already up to date (${installed}).`);
65035
+ return 0;
65036
+ }
65037
+ }
65038
+ }
65039
+ if (opts.isTTY && !opts.force && !opts.compile && (!current || compareSemver(current, targetSemver) < 0)) {
65014
65040
  const action = await (opts.promptUpdate ?? promptUpdate)({ latest: target, highestAvailable: target });
65015
65041
  if (action === "cancel") {
65016
65042
  ctx.say("Update cancelled.");
@@ -65863,7 +65889,7 @@ function runPolicy(ctx, argv, io2) {
65863
65889
  }
65864
65890
 
65865
65891
  // src/commands/revert.ts
65866
- import { existsSync as existsSync15, lstatSync as lstatSync7, readdirSync as readdirSync4, rmSync as rmSync6, symlinkSync as symlinkSync2 } from "node:fs";
65892
+ import { existsSync as existsSync15, lstatSync as lstatSync7, readdirSync as readdirSync4, rmSync as rmSync7, symlinkSync as symlinkSync2 } from "node:fs";
65867
65893
  import { join as join21 } from "node:path";
65868
65894
  function safeIsSymlink(p2) {
65869
65895
  try {
@@ -65886,7 +65912,7 @@ function revert(ctx) {
65886
65912
  function removeGenerations(ctx, actions) {
65887
65913
  const { currentGeneration, generationsDir } = ctx.paths;
65888
65914
  if (existsSync15(currentGeneration) || safeIsSymlink(currentGeneration)) {
65889
- rmSync6(currentGeneration, { recursive: true, force: true });
65915
+ rmSync7(currentGeneration, { recursive: true, force: true });
65890
65916
  actions.push(`removed generation pointer ${currentGeneration}`);
65891
65917
  }
65892
65918
  if (!existsSync15(generationsDir))
@@ -65897,12 +65923,12 @@ function removeGenerations(ctx, actions) {
65897
65923
  actions.push(`${dir} is not a cxstatusline generation; left in place`);
65898
65924
  continue;
65899
65925
  }
65900
- rmSync6(dir, { recursive: true, force: true });
65926
+ rmSync7(dir, { recursive: true, force: true });
65901
65927
  removed += 1;
65902
65928
  }
65903
65929
  actions.push(`removed ${removed} cxstatusline generation${removed === 1 ? "" : "s"} from ${generationsDir}`);
65904
65930
  if (readdirSync4(generationsDir).length === 0)
65905
- rmSync6(generationsDir, { recursive: true, force: true });
65931
+ rmSync7(generationsDir, { recursive: true, force: true });
65906
65932
  }
65907
65933
  var OWNED_LIBEXEC_PREFIXES = ["current.", "staging-", "download-", "compiled-"];
65908
65934
  function removeStagingDebris(ctx, actions) {
@@ -65911,7 +65937,7 @@ function removeStagingDebris(ctx, actions) {
65911
65937
  return;
65912
65938
  const debris = readdirSync4(libexecDir).filter((n) => OWNED_LIBEXEC_PREFIXES.some((p2) => n.startsWith(p2)));
65913
65939
  for (const name of debris)
65914
- rmSync6(join21(libexecDir, name), { recursive: true, force: true });
65940
+ rmSync7(join21(libexecDir, name), { recursive: true, force: true });
65915
65941
  if (debris.length > 0) {
65916
65942
  actions.push(`removed ${debris.length} leftover staging entr${debris.length === 1 ? "y" : "ies"} from ${libexecDir}`);
65917
65943
  }
@@ -65925,7 +65951,7 @@ function revertLocked(ctx) {
65925
65951
  const w2 = ctx.paths.wrapperPath;
65926
65952
  if (existsSync15(w2) || safeIsSymlink(w2)) {
65927
65953
  if (isOurWrapper(w2)) {
65928
- rmSync6(w2);
65954
+ rmSync7(w2);
65929
65955
  actions.push(`removed wrapper ${w2}`);
65930
65956
  if (state.launcher_restore?.kind === "symlink") {
65931
65957
  symlinkSync2(state.launcher_restore.target, w2);
@@ -65940,11 +65966,11 @@ function revertLocked(ctx) {
65940
65966
  removeGenerations(ctx, actions);
65941
65967
  removeStagingDebris(ctx, actions);
65942
65968
  if (existsSync15(ctx.paths.patchedBin)) {
65943
- rmSync6(ctx.paths.patchedBin);
65969
+ rmSync7(ctx.paths.patchedBin);
65944
65970
  actions.push(`removed patched binary ${ctx.paths.patchedBin}`);
65945
65971
  }
65946
65972
  if (existsSync15(ctx.paths.patchedCodeModeHost)) {
65947
- rmSync6(ctx.paths.patchedCodeModeHost);
65973
+ rmSync7(ctx.paths.patchedCodeModeHost);
65948
65974
  actions.push(`removed Code Mode host ${ctx.paths.patchedCodeModeHost}`);
65949
65975
  }
65950
65976
  try {
@@ -68465,6 +68491,154 @@ function readMemoryUsage(deps, nowMs) {
68465
68491
  }
68466
68492
  }
68467
68493
 
68494
+ // src/commands/update-tool.ts
68495
+ import { spawnSync as spawnSync5 } from "node:child_process";
68496
+ import { existsSync as existsSync17, realpathSync as realpathSync4 } from "node:fs";
68497
+ import { dirname as dirname11, join as join23 } from "node:path";
68498
+ async function defaultFetchLatestVersion() {
68499
+ const controller = new AbortController;
68500
+ const timer = setTimeout(() => controller.abort(), 5000);
68501
+ try {
68502
+ const res = await fetch("https://registry.npmjs.org/cxstatusline/latest", {
68503
+ headers: { Accept: "application/json" },
68504
+ signal: controller.signal
68505
+ });
68506
+ if (!res.ok)
68507
+ return null;
68508
+ const data = await res.json();
68509
+ return typeof data.version === "string" ? data.version : null;
68510
+ } catch {
68511
+ return null;
68512
+ } finally {
68513
+ clearTimeout(timer);
68514
+ }
68515
+ }
68516
+ function detectInstallType(binaryPath = process.argv[1]) {
68517
+ if (!binaryPath)
68518
+ return { type: "npm" };
68519
+ try {
68520
+ let resolved = binaryPath;
68521
+ try {
68522
+ resolved = realpathSync4(binaryPath);
68523
+ } catch {}
68524
+ let dir = dirname11(resolved);
68525
+ for (let i = 0;i < 5; i++) {
68526
+ if (existsSync17(join23(dir, ".git")) && existsSync17(join23(dir, "package.json"))) {
68527
+ return { type: "git", repoDir: dir };
68528
+ }
68529
+ const parent = dirname11(dir);
68530
+ if (parent === dir)
68531
+ break;
68532
+ dir = parent;
68533
+ }
68534
+ if (binaryPath.includes(".bun") || resolved.includes(".bun")) {
68535
+ return { type: "bun" };
68536
+ }
68537
+ if (binaryPath.includes("pnpm") || resolved.includes("pnpm")) {
68538
+ return { type: "pnpm" };
68539
+ }
68540
+ } catch {}
68541
+ return { type: "npm" };
68542
+ }
68543
+ function defaultExecCommand(cmd, args) {
68544
+ const res = spawnSync5(cmd, args, { encoding: "utf8" });
68545
+ return {
68546
+ status: res.status ?? (res.error ? 1 : 0),
68547
+ stdout: res.stdout || "",
68548
+ stderr: res.stderr || (res.error ? res.error.message : "")
68549
+ };
68550
+ }
68551
+ async function runUpdateTool(flags, io2, deps = {}) {
68552
+ const checkOnly = flags.includes("--check");
68553
+ const currentVersionStr = deps.currentVersion ?? VERSION;
68554
+ const currentSemver = parseSemver(currentVersionStr);
68555
+ if (!currentSemver) {
68556
+ io2.stderr(`Invalid current version: ${currentVersionStr}
68557
+ `);
68558
+ return 1;
68559
+ }
68560
+ io2.stdout(`Checking for cxstatusline updates...
68561
+ `);
68562
+ const fetcher = deps.fetchLatestVersion ?? defaultFetchLatestVersion;
68563
+ const latest = await fetcher();
68564
+ if (!latest) {
68565
+ io2.stderr(`Failed to check for updates: could not reach npm registry.
68566
+ `);
68567
+ return 1;
68568
+ }
68569
+ const latestSemver = parseSemver(latest);
68570
+ if (!latestSemver) {
68571
+ io2.stderr(`Invalid version received from registry: ${latest}
68572
+ `);
68573
+ return 1;
68574
+ }
68575
+ if (compareSemver(latestSemver, currentSemver) <= 0) {
68576
+ io2.stdout(`cxstatusline is already up to date (${currentVersionStr}).
68577
+ `);
68578
+ return 0;
68579
+ }
68580
+ if (checkOnly) {
68581
+ io2.stdout(`Update available: ${currentVersionStr} -> ${latest}
68582
+ `);
68583
+ io2.stdout("Run `cxstatusline update` to upgrade the tool.\n");
68584
+ return 0;
68585
+ }
68586
+ const detector = deps.detectInstallType ?? (() => detectInstallType());
68587
+ const installInfo = detector();
68588
+ const exec2 = deps.execCommand ?? defaultExecCommand;
68589
+ if (installInfo.type === "git" && installInfo.repoDir) {
68590
+ io2.stdout(`Updating cxstatusline from git repository at ${installInfo.repoDir}...
68591
+ `);
68592
+ const pull2 = exec2("git", ["-C", installInfo.repoDir, "pull", "origin", "main"]);
68593
+ if (pull2.status !== 0) {
68594
+ io2.stderr(`Failed to update cxstatusline via git pull:
68595
+ ${pull2.stderr || pull2.stdout}
68596
+ `);
68597
+ return 1;
68598
+ }
68599
+ const install2 = exec2("bun", ["--cwd", installInfo.repoDir, "install", "--frozen-lockfile"]);
68600
+ if (install2.status !== 0) {
68601
+ io2.stderr(`Failed to run bun install in repo:
68602
+ ${install2.stderr || install2.stdout}
68603
+ `);
68604
+ return 1;
68605
+ }
68606
+ const build = exec2("bun", ["--cwd", installInfo.repoDir, "run", "build"]);
68607
+ if (build.status !== 0) {
68608
+ io2.stderr(`Failed to build cxstatusline in repo:
68609
+ ${build.stderr || build.stdout}
68610
+ `);
68611
+ return 1;
68612
+ }
68613
+ io2.stdout(`Successfully updated cxstatusline from git checkout.
68614
+ `);
68615
+ return 0;
68616
+ }
68617
+ let command = "npm";
68618
+ let args = ["install", "-g", "cxstatusline@latest"];
68619
+ if (installInfo.type === "bun") {
68620
+ command = "bun";
68621
+ args = ["add", "-g", "cxstatusline@latest"];
68622
+ } else if (installInfo.type === "pnpm") {
68623
+ command = "pnpm";
68624
+ args = ["add", "-g", "cxstatusline@latest"];
68625
+ }
68626
+ io2.stdout(`Updating cxstatusline via ${command} (${command} ${args.join(" ")})...
68627
+ `);
68628
+ const result2 = exec2(command, args);
68629
+ if (result2.status !== 0) {
68630
+ io2.stderr(`Failed to update cxstatusline:
68631
+ ${result2.stderr || result2.stdout}
68632
+ `);
68633
+ io2.stderr(`You can try updating manually with: ${command} ${args.join(" ")}
68634
+ `);
68635
+ return 1;
68636
+ }
68637
+ io2.stdout(`Successfully updated cxstatusline to ${latest}.
68638
+ `);
68639
+ return 0;
68640
+ }
68641
+
68468
68642
  // src/main.ts
68469
68643
  var USAGE = `usage: cxstatusline [command]
68470
68644
 
@@ -68474,7 +68648,8 @@ var USAGE = `usage: cxstatusline [command]
68474
68648
  install the published Codex pair (--compile builds it from source)
68475
68649
  patch [--force] build and install the patched Codex from source
68476
68650
  patch --simulate-drift <v> record <v> as the installed version so the next session sees drift
68477
- update [--compile|--force] install the latest supported patched Codex pair
68651
+ update [--check] update cxstatusline tool to the latest version
68652
+ upgrade [--compile|--force] upgrade the patched Codex pair to the latest supported version
68478
68653
  hook [install|uninstall] manage the SessionStart entry; bare 'hook' is what Codex runs
68479
68654
  doctor report toolchain, drift, hook and wrapper state
68480
68655
  policy [get|set <policy>] view or update policy (every, stable-minors, manual)
@@ -68617,12 +68792,44 @@ async function installCommand(argv, io2, deps) {
68617
68792
  return runInstall(ctx, { compile: compile3, codexVersion }, deps.transport);
68618
68793
  }
68619
68794
  async function updateCommand(argv, io2, deps) {
68795
+ const flags = argv.slice(1);
68796
+ const codexFlags = new Set(["--compile", "--force", "-y", "--yes"]);
68797
+ if (flags.some((f2) => codexFlags.has(f2) || f2.startsWith("--codex-version"))) {
68798
+ io2.stdout(`Notice: 'cxstatusline upgrade' is now used to upgrade the patched Codex pair.
68799
+ Forwarding to 'upgrade'...
68800
+
68801
+ `);
68802
+ return upgradeCommand(argv, io2, deps);
68803
+ }
68804
+ const allowed = new Set(["--check", "-h", "--help"]);
68805
+ if (flags.some((f2) => !allowed.has(f2))) {
68806
+ io2.stderr(USAGE);
68807
+ return 2;
68808
+ }
68809
+ const updater = deps.updateTool ?? runUpdateTool;
68810
+ return updater(flags, io2, { fetchLatestVersion: deps.fetchLatestToolVersion });
68811
+ }
68812
+ async function upgradeCommand(argv, io2, deps) {
68620
68813
  const flags = argv.slice(1);
68621
68814
  const allowed = new Set(["--compile", "--force", "-y", "--yes"]);
68622
68815
  if (flags.some((f2) => !allowed.has(f2))) {
68623
68816
  io2.stderr(USAGE);
68624
68817
  return 2;
68625
68818
  }
68819
+ try {
68820
+ const latest = await (deps.fetchLatestToolVersion ?? defaultFetchLatestVersion)();
68821
+ if (latest) {
68822
+ const parsedLatest = parseSemver(latest);
68823
+ const parsedCurrent = parseSemver(VERSION);
68824
+ if (parsedLatest && parsedCurrent && compareSemver(parsedLatest, parsedCurrent) === 1) {
68825
+ io2.stdout(`
68826
+ \uD83D\uDCA1 Note: A newer version of cxstatusline is available (${VERSION} → ${latest}).
68827
+ Run 'cxstatusline update' to update the tool for the newest Codex patches.
68828
+
68829
+ `);
68830
+ }
68831
+ }
68832
+ } catch {}
68626
68833
  return runUpdate(contextFor(io2, deps), {
68627
68834
  compile: flags.includes("--compile"),
68628
68835
  force: flags.includes("--force") || flags.includes("-y") || flags.includes("--yes"),
@@ -68693,6 +68900,8 @@ async function main(argv, io2, deps = {}) {
68693
68900
  return patchCommand(argv, io2, deps);
68694
68901
  if (cmd === "update")
68695
68902
  return updateCommand(argv, io2, deps);
68903
+ if (cmd === "upgrade")
68904
+ return upgradeCommand(argv, io2, deps);
68696
68905
  if (cmd === "install")
68697
68906
  return installCommand(argv, io2, deps);
68698
68907
  if (cmd === "hook" && (argv[1] === "install" || argv[1] === "uninstall")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cxstatusline",
3
- "version": "0.9.1",
3
+ "version": "0.10.1",
4
4
  "description": "Customizable statusline for OpenAI Codex CLI",
5
5
  "license": "MIT",
6
6
  "repository": {