cxstatusline 0.9.0 → 0.10.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/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)
151
157
 
152
158
  ```sh
153
- cxstatusline update
159
+ cxstatusline update # Updates cxstatusline to the latest version
160
+ cxstatusline update --check # Checks for available tool updates without installing
154
161
  ```
155
162
 
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.
163
+ `cxstatusline update` automatically detects your install method (`npm`, `bun`, or `git checkout`) and updates the CLI tool.
164
+
165
+ ### Upgrading Patched Codex
157
166
 
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.
167
+ ```sh
168
+ cxstatusline upgrade
169
+ ```
170
+
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.
172
+
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
 
@@ -246,3 +262,12 @@ cxstatusline is [MIT licensed](LICENSE). See [SECURITY.md](SECURITY.md) for secu
246
262
  - 🌐 **Web Playground:** [cxstatusline.adrijshikhar.dev](https://cxstatusline.adrijshikhar.dev)
247
263
  - 💬 **Discussions & Ideas:** [github.com/adrijshikhar/cxstatusline/discussions](https://github.com/adrijshikhar/cxstatusline/discussions)
248
264
  - 📦 **npm Package:** [npmjs.com/package/cxstatusline](https://www.npmjs.com/package/cxstatusline)
265
+
266
+ ### Prebuilt build machine
267
+
268
+ All Codex prebuilt jobs run on the owner's M5 Pro (`192.168.1.65`, Actions labels
269
+ `self-hosted`, `macOS`, `ARM64`, `m5-pro`). macOS builds natively; Linux builds in
270
+ Docker on that same M5. Keep the laptop and runner active until the workflow finishes.
271
+ An offline M5 leaves jobs queued; there is no hosted fallback. Platform builds run
272
+ sequentially, preserving 3 native Rust compiler jobs and 8 inside Docker. Dispatch from a ref containing this policy;
273
+ older release tags may still contain the removed hosted-runner option.
@@ -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.0";
59011
- var SOURCE_COMMIT = /^[0-9a-f]{40}$/.test("6a7b82efae2605ec4e4346c7d482b7d5b7734347") ? "6a7b82efae2605ec4e4346c7d482b7d5b7734347" : null;
59010
+ var VERSION = "0.10.0";
59011
+ var SOURCE_COMMIT = /^[0-9a-f]{40}$/.test("2a36f98f9f4d2b98638cc4ba9380253e1407c9bf") ? "2a36f98f9f4d2b98638cc4ba9380253e1407c9bf" : null;
59012
59012
  var SOURCE_DIRTY = false;
59013
59013
 
59014
59014
  // src/context.ts
@@ -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",
@@ -68465,6 +68465,154 @@ function readMemoryUsage(deps, nowMs) {
68465
68465
  }
68466
68466
  }
68467
68467
 
68468
+ // src/commands/update-tool.ts
68469
+ import { spawnSync as spawnSync5 } from "node:child_process";
68470
+ import { existsSync as existsSync17, realpathSync as realpathSync4 } from "node:fs";
68471
+ import { dirname as dirname11, join as join23 } from "node:path";
68472
+ async function defaultFetchLatestVersion() {
68473
+ const controller = new AbortController;
68474
+ const timer = setTimeout(() => controller.abort(), 5000);
68475
+ try {
68476
+ const res = await fetch("https://registry.npmjs.org/cxstatusline/latest", {
68477
+ headers: { Accept: "application/json" },
68478
+ signal: controller.signal
68479
+ });
68480
+ if (!res.ok)
68481
+ return null;
68482
+ const data = await res.json();
68483
+ return typeof data.version === "string" ? data.version : null;
68484
+ } catch {
68485
+ return null;
68486
+ } finally {
68487
+ clearTimeout(timer);
68488
+ }
68489
+ }
68490
+ function detectInstallType(binaryPath = process.argv[1]) {
68491
+ if (!binaryPath)
68492
+ return { type: "npm" };
68493
+ try {
68494
+ let resolved = binaryPath;
68495
+ try {
68496
+ resolved = realpathSync4(binaryPath);
68497
+ } catch {}
68498
+ let dir = dirname11(resolved);
68499
+ for (let i = 0;i < 5; i++) {
68500
+ if (existsSync17(join23(dir, ".git")) && existsSync17(join23(dir, "package.json"))) {
68501
+ return { type: "git", repoDir: dir };
68502
+ }
68503
+ const parent = dirname11(dir);
68504
+ if (parent === dir)
68505
+ break;
68506
+ dir = parent;
68507
+ }
68508
+ if (binaryPath.includes(".bun") || resolved.includes(".bun")) {
68509
+ return { type: "bun" };
68510
+ }
68511
+ if (binaryPath.includes("pnpm") || resolved.includes("pnpm")) {
68512
+ return { type: "pnpm" };
68513
+ }
68514
+ } catch {}
68515
+ return { type: "npm" };
68516
+ }
68517
+ function defaultExecCommand(cmd, args) {
68518
+ const res = spawnSync5(cmd, args, { encoding: "utf8" });
68519
+ return {
68520
+ status: res.status ?? (res.error ? 1 : 0),
68521
+ stdout: res.stdout || "",
68522
+ stderr: res.stderr || (res.error ? res.error.message : "")
68523
+ };
68524
+ }
68525
+ async function runUpdateTool(flags, io2, deps = {}) {
68526
+ const checkOnly = flags.includes("--check");
68527
+ const currentVersionStr = deps.currentVersion ?? VERSION;
68528
+ const currentSemver = parseSemver(currentVersionStr);
68529
+ if (!currentSemver) {
68530
+ io2.stderr(`Invalid current version: ${currentVersionStr}
68531
+ `);
68532
+ return 1;
68533
+ }
68534
+ io2.stdout(`Checking for cxstatusline updates...
68535
+ `);
68536
+ const fetcher = deps.fetchLatestVersion ?? defaultFetchLatestVersion;
68537
+ const latest = await fetcher();
68538
+ if (!latest) {
68539
+ io2.stderr(`Failed to check for updates: could not reach npm registry.
68540
+ `);
68541
+ return 1;
68542
+ }
68543
+ const latestSemver = parseSemver(latest);
68544
+ if (!latestSemver) {
68545
+ io2.stderr(`Invalid version received from registry: ${latest}
68546
+ `);
68547
+ return 1;
68548
+ }
68549
+ if (compareSemver(latestSemver, currentSemver) <= 0) {
68550
+ io2.stdout(`cxstatusline is already up to date (${currentVersionStr}).
68551
+ `);
68552
+ return 0;
68553
+ }
68554
+ if (checkOnly) {
68555
+ io2.stdout(`Update available: ${currentVersionStr} -> ${latest}
68556
+ `);
68557
+ io2.stdout("Run `cxstatusline update` to upgrade the tool.\n");
68558
+ return 0;
68559
+ }
68560
+ const detector = deps.detectInstallType ?? (() => detectInstallType());
68561
+ const installInfo = detector();
68562
+ const exec2 = deps.execCommand ?? defaultExecCommand;
68563
+ if (installInfo.type === "git" && installInfo.repoDir) {
68564
+ io2.stdout(`Updating cxstatusline from git repository at ${installInfo.repoDir}...
68565
+ `);
68566
+ const pull2 = exec2("git", ["-C", installInfo.repoDir, "pull", "origin", "main"]);
68567
+ if (pull2.status !== 0) {
68568
+ io2.stderr(`Failed to update cxstatusline via git pull:
68569
+ ${pull2.stderr || pull2.stdout}
68570
+ `);
68571
+ return 1;
68572
+ }
68573
+ const install2 = exec2("bun", ["--cwd", installInfo.repoDir, "install", "--frozen-lockfile"]);
68574
+ if (install2.status !== 0) {
68575
+ io2.stderr(`Failed to run bun install in repo:
68576
+ ${install2.stderr || install2.stdout}
68577
+ `);
68578
+ return 1;
68579
+ }
68580
+ const build = exec2("bun", ["--cwd", installInfo.repoDir, "run", "build"]);
68581
+ if (build.status !== 0) {
68582
+ io2.stderr(`Failed to build cxstatusline in repo:
68583
+ ${build.stderr || build.stdout}
68584
+ `);
68585
+ return 1;
68586
+ }
68587
+ io2.stdout(`Successfully updated cxstatusline from git checkout.
68588
+ `);
68589
+ return 0;
68590
+ }
68591
+ let command = "npm";
68592
+ let args = ["install", "-g", "cxstatusline@latest"];
68593
+ if (installInfo.type === "bun") {
68594
+ command = "bun";
68595
+ args = ["add", "-g", "cxstatusline@latest"];
68596
+ } else if (installInfo.type === "pnpm") {
68597
+ command = "pnpm";
68598
+ args = ["add", "-g", "cxstatusline@latest"];
68599
+ }
68600
+ io2.stdout(`Updating cxstatusline via ${command} (${command} ${args.join(" ")})...
68601
+ `);
68602
+ const result2 = exec2(command, args);
68603
+ if (result2.status !== 0) {
68604
+ io2.stderr(`Failed to update cxstatusline:
68605
+ ${result2.stderr || result2.stdout}
68606
+ `);
68607
+ io2.stderr(`You can try updating manually with: ${command} ${args.join(" ")}
68608
+ `);
68609
+ return 1;
68610
+ }
68611
+ io2.stdout(`Successfully updated cxstatusline to ${latest}.
68612
+ `);
68613
+ return 0;
68614
+ }
68615
+
68468
68616
  // src/main.ts
68469
68617
  var USAGE = `usage: cxstatusline [command]
68470
68618
 
@@ -68474,7 +68622,8 @@ var USAGE = `usage: cxstatusline [command]
68474
68622
  install the published Codex pair (--compile builds it from source)
68475
68623
  patch [--force] build and install the patched Codex from source
68476
68624
  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
68625
+ update [--check] update cxstatusline tool to the latest version
68626
+ upgrade [--compile|--force] upgrade the patched Codex pair to the latest supported version
68478
68627
  hook [install|uninstall] manage the SessionStart entry; bare 'hook' is what Codex runs
68479
68628
  doctor report toolchain, drift, hook and wrapper state
68480
68629
  policy [get|set <policy>] view or update policy (every, stable-minors, manual)
@@ -68617,12 +68766,44 @@ async function installCommand(argv, io2, deps) {
68617
68766
  return runInstall(ctx, { compile: compile3, codexVersion }, deps.transport);
68618
68767
  }
68619
68768
  async function updateCommand(argv, io2, deps) {
68769
+ const flags = argv.slice(1);
68770
+ const codexFlags = new Set(["--compile", "--force", "-y", "--yes"]);
68771
+ if (flags.some((f2) => codexFlags.has(f2) || f2.startsWith("--codex-version"))) {
68772
+ io2.stdout(`Notice: 'cxstatusline upgrade' is now used to upgrade the patched Codex pair.
68773
+ Forwarding to 'upgrade'...
68774
+
68775
+ `);
68776
+ return upgradeCommand(argv, io2, deps);
68777
+ }
68778
+ const allowed = new Set(["--check", "-h", "--help"]);
68779
+ if (flags.some((f2) => !allowed.has(f2))) {
68780
+ io2.stderr(USAGE);
68781
+ return 2;
68782
+ }
68783
+ const updater = deps.updateTool ?? runUpdateTool;
68784
+ return updater(flags, io2, { fetchLatestVersion: deps.fetchLatestToolVersion });
68785
+ }
68786
+ async function upgradeCommand(argv, io2, deps) {
68620
68787
  const flags = argv.slice(1);
68621
68788
  const allowed = new Set(["--compile", "--force", "-y", "--yes"]);
68622
68789
  if (flags.some((f2) => !allowed.has(f2))) {
68623
68790
  io2.stderr(USAGE);
68624
68791
  return 2;
68625
68792
  }
68793
+ try {
68794
+ const latest = await (deps.fetchLatestToolVersion ?? defaultFetchLatestVersion)();
68795
+ if (latest) {
68796
+ const parsedLatest = parseSemver(latest);
68797
+ const parsedCurrent = parseSemver(VERSION);
68798
+ if (parsedLatest && parsedCurrent && compareSemver(parsedLatest, parsedCurrent) === 1) {
68799
+ io2.stdout(`
68800
+ \uD83D\uDCA1 Note: A newer version of cxstatusline is available (${VERSION} → ${latest}).
68801
+ Run 'cxstatusline update' to update the tool for the newest Codex patches.
68802
+
68803
+ `);
68804
+ }
68805
+ }
68806
+ } catch {}
68626
68807
  return runUpdate(contextFor(io2, deps), {
68627
68808
  compile: flags.includes("--compile"),
68628
68809
  force: flags.includes("--force") || flags.includes("-y") || flags.includes("--yes"),
@@ -68693,6 +68874,8 @@ async function main(argv, io2, deps = {}) {
68693
68874
  return patchCommand(argv, io2, deps);
68694
68875
  if (cmd === "update")
68695
68876
  return updateCommand(argv, io2, deps);
68877
+ if (cmd === "upgrade")
68878
+ return upgradeCommand(argv, io2, deps);
68696
68879
  if (cmd === "install")
68697
68880
  return installCommand(argv, io2, deps);
68698
68881
  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.0",
3
+ "version": "0.10.0",
4
4
  "description": "Customizable statusline for OpenAI Codex CLI",
5
5
  "license": "MIT",
6
6
  "repository": {