cxstatusline 0.8.0 → 0.9.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.
@@ -53400,6 +53400,7 @@ class Ink {
53400
53400
  log;
53401
53401
  throttledLog;
53402
53402
  isScreenReaderEnabled;
53403
+ isInCi;
53403
53404
  isUnmounted;
53404
53405
  lastOutput;
53405
53406
  lastOutputHeight;
@@ -53412,6 +53413,7 @@ class Ink {
53412
53413
  constructor(options) {
53413
53414
  autoBind(this);
53414
53415
  this.options = options;
53416
+ this.isInCi = options.isCI ?? is_in_ci_default;
53415
53417
  this.rootNode = createNode("ink-root");
53416
53418
  this.rootNode.onComputeLayout = this.calculateLayout;
53417
53419
  this.isScreenReaderEnabled = options.isScreenReaderEnabled ?? process12.env["INK_SCREEN_READER"] === "true";
@@ -53442,7 +53444,7 @@ class Ink {
53442
53444
  if (options.patchConsole) {
53443
53445
  this.patchConsole();
53444
53446
  }
53445
- if (!is_in_ci_default) {
53447
+ if (!this.isInCi) {
53446
53448
  options.stdout.on("resize", this.resized);
53447
53449
  this.unsubscribeResize = () => {
53448
53450
  options.stdout.off("resize", this.resized);
@@ -53475,7 +53477,7 @@ class Ink {
53475
53477
  this.options.stdout.write(this.fullStaticOutput + output2);
53476
53478
  return;
53477
53479
  }
53478
- if (is_in_ci_default) {
53480
+ if (this.isInCi) {
53479
53481
  if (hasStaticOutput) {
53480
53482
  this.options.stdout.write(staticOutput);
53481
53483
  }
@@ -53486,7 +53488,7 @@ class Ink {
53486
53488
  if (hasStaticOutput) {
53487
53489
  this.fullStaticOutput += staticOutput;
53488
53490
  }
53489
- if (this.lastOutputHeight >= this.options.stdout.rows) {
53491
+ if (!this.options.preserveScrollback && this.lastOutputHeight >= this.options.stdout.rows) {
53490
53492
  this.options.stdout.write(exports_base.clearTerminal + this.fullStaticOutput + output2 + `
53491
53493
  `);
53492
53494
  this.lastOutput = output2;
@@ -53518,7 +53520,7 @@ class Ink {
53518
53520
  this.options.stdout.write(data + this.fullStaticOutput + this.lastOutput);
53519
53521
  return;
53520
53522
  }
53521
- if (is_in_ci_default) {
53523
+ if (this.isInCi) {
53522
53524
  this.options.stdout.write(data);
53523
53525
  return;
53524
53526
  }
@@ -53535,7 +53537,7 @@ class Ink {
53535
53537
  this.options.stdout.write(this.fullStaticOutput + this.lastOutput);
53536
53538
  return;
53537
53539
  }
53538
- if (is_in_ci_default) {
53540
+ if (this.isInCi) {
53539
53541
  this.options.stderr.write(data);
53540
53542
  return;
53541
53543
  }
@@ -53556,7 +53558,7 @@ class Ink {
53556
53558
  if (typeof this.unsubscribeResize === "function") {
53557
53559
  this.unsubscribeResize();
53558
53560
  }
53559
- if (is_in_ci_default) {
53561
+ if (this.isInCi) {
53560
53562
  this.options.stdout.write(this.lastOutput + `
53561
53563
  `);
53562
53564
  } else if (!this.options.debug) {
@@ -53580,7 +53582,7 @@ class Ink {
53580
53582
  return this.exitPromise;
53581
53583
  }
53582
53584
  clear() {
53583
- if (!is_in_ci_default && !this.options.debug) {
53585
+ if (!this.isInCi && !this.options.debug) {
53584
53586
  this.log.clear();
53585
53587
  }
53586
53588
  }
@@ -59005,14 +59007,14 @@ function runRefreshCommand(cacheKey2, deps) {
59005
59007
  return 0;
59006
59008
  }
59007
59009
  // src/version-info.ts
59008
- var VERSION = "0.8.0";
59009
- var SOURCE_COMMIT = /^[0-9a-f]{40}$/.test("ac126bc0e09a58856e40452e31bfc62c294eee36") ? "ac126bc0e09a58856e40452e31bfc62c294eee36" : null;
59010
+ var VERSION = "0.9.0";
59011
+ var SOURCE_COMMIT = /^[0-9a-f]{40}$/.test("6a7b82efae2605ec4e4346c7d482b7d5b7734347") ? "6a7b82efae2605ec4e4346c7d482b7d5b7734347" : null;
59010
59012
  var SOURCE_DIRTY = false;
59011
59013
 
59012
59014
  // src/context.ts
59013
59015
  import { existsSync as existsSync3, realpathSync } from "node:fs";
59014
59016
  import { spawnSync as spawnSync4 } from "node:child_process";
59015
- import { dirname as dirname5, join as join8 } from "node:path";
59017
+ import { fileURLToPath } from "node:url";
59016
59018
 
59017
59019
  // src/patch/preflight.ts
59018
59020
  import { accessSync, constants as constants2, existsSync as existsSync2, statfsSync } from "node:fs";
@@ -59139,7 +59141,7 @@ function realContext(env3, io) {
59139
59141
  which: deps.which,
59140
59142
  freeBytes: deps.freeBytes,
59141
59143
  cxBin: own2,
59142
- patchesDir: join8(dirname5(realpathSync(own2)), "..", "patches"),
59144
+ patchesDir: fileURLToPath(new URL("../patches", import.meta.url)),
59143
59145
  now: () => new Date,
59144
59146
  log: io.log,
59145
59147
  say: io.say
@@ -59148,11 +59150,11 @@ function realContext(env3, io) {
59148
59150
 
59149
59151
  // src/patch/run.ts
59150
59152
  import { appendFileSync, mkdirSync as mkdirSync8 } from "node:fs";
59151
- import { join as join19 } from "node:path";
59153
+ import { join as join18 } from "node:path";
59152
59154
 
59153
59155
  // src/lock.ts
59154
59156
  import { closeSync, existsSync as existsSync4, mkdirSync as mkdirSync3, openSync, readFileSync as readFileSync4, unlinkSync as unlinkSync3, writeSync } from "node:fs";
59155
- import { dirname as dirname6 } from "node:path";
59157
+ import { dirname as dirname5 } from "node:path";
59156
59158
  function pidAlive(pid) {
59157
59159
  try {
59158
59160
  process.kill(pid, 0);
@@ -59172,7 +59174,7 @@ function lockHolder(file2) {
59172
59174
  }
59173
59175
  }
59174
59176
  function acquireLock(file2, isAlive = pidAlive) {
59175
- mkdirSync3(dirname6(file2), { recursive: true });
59177
+ mkdirSync3(dirname5(file2), { recursive: true });
59176
59178
  for (let attempt2 = 0;attempt2 < 2; attempt2++) {
59177
59179
  try {
59178
59180
  const fd = openSync(file2, "wx");
@@ -59243,7 +59245,7 @@ function needsRepatch(upstream, patched, policy) {
59243
59245
  if (policy === "manual")
59244
59246
  return false;
59245
59247
  if (policy === "every")
59246
- return patched === null || compareSemver(upstream, patched) !== 0;
59248
+ return patched === null || compareSemver(upstream, patched) > 0;
59247
59249
  if (upstream.pre !== null)
59248
59250
  return false;
59249
59251
  if (patched === null)
@@ -59258,12 +59260,12 @@ function behindWithinMinor(upstream, patched) {
59258
59260
  // src/distribution/prebuilt.ts
59259
59261
  import { createHash as createHash4 } from "node:crypto";
59260
59262
  import { chmodSync as chmodSync2, copyFileSync as copyFileSync2, mkdirSync as mkdirSync5, mkdtempSync, readFileSync as readFileSync6, renameSync as renameSync4, rmSync as rmSync2 } from "node:fs";
59261
- import { join as join12 } from "node:path";
59263
+ import { join as join11 } from "node:path";
59262
59264
 
59263
59265
  // src/patch/generation.ts
59264
59266
  import { chmodSync, copyFileSync, existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync5, readdirSync as readdirSync2, readlinkSync, realpathSync as realpathSync2, renameSync as renameSync2, rmSync, statSync, symlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
59265
59267
  import { createHash as createHash2, randomBytes as randomBytes2 } from "node:crypto";
59266
- import { dirname as dirname7, isAbsolute, join as join9, resolve as resolve2, sep } from "node:path";
59268
+ import { dirname as dirname6, isAbsolute, join as join8, resolve as resolve2, sep } from "node:path";
59267
59269
  var INSTALLATION_FILE = "installation.json";
59268
59270
  var SAFE_SEGMENT = /^[A-Za-z0-9][A-Za-z0-9._+-]*$/;
59269
59271
  function digestOf(file2) {
@@ -59282,7 +59284,7 @@ function nearestExisting2(p) {
59282
59284
  statSync(cur);
59283
59285
  return cur;
59284
59286
  } catch {
59285
- const parent = dirname7(cur);
59287
+ const parent = dirname6(cur);
59286
59288
  if (parent === cur)
59287
59289
  return cur;
59288
59290
  cur = parent;
@@ -59301,7 +59303,7 @@ function validateStaging(pair) {
59301
59303
  throw new Error(`prepared pair has an unusable codexVersion "${pair.codexVersion}"`);
59302
59304
  }
59303
59305
  for (const name of GENERATION_EXECUTABLES) {
59304
- const file2 = join9(pair.directory, name);
59306
+ const file2 = join8(pair.directory, name);
59305
59307
  if (!existsSync5(file2))
59306
59308
  throw new Error(`staged pair is missing ${name}`);
59307
59309
  const want = pair.provenance.executables[name];
@@ -59312,7 +59314,7 @@ function validateStaging(pair) {
59312
59314
  }
59313
59315
  if (pair.provenance.source === "prebuilt") {
59314
59316
  for (const name of GENERATION_LEGAL_FILES) {
59315
- if (!existsSync5(join9(pair.directory, name)))
59317
+ if (!existsSync5(join8(pair.directory, name)))
59316
59318
  throw new Error(`prebuilt pair is missing ${name}`);
59317
59319
  }
59318
59320
  }
@@ -59322,8 +59324,8 @@ function installationRecord(pair) {
59322
59324
  return record2;
59323
59325
  }
59324
59326
  function copyInto(from, into, name, mode, expected) {
59325
- const target = join9(into, name);
59326
- copyFileSync(join9(from, name), target);
59327
+ const target = join8(into, name);
59328
+ copyFileSync(join8(from, name), target);
59327
59329
  chmodSync(target, mode);
59328
59330
  if (!expected)
59329
59331
  return;
@@ -59333,7 +59335,7 @@ function copyInto(from, into, name, mode, expected) {
59333
59335
  }
59334
59336
  }
59335
59337
  function commitJson(file2, value, rename2) {
59336
- const tmp = join9(dirname7(file2), `.${process.pid}.${randomBytes2(4).toString("hex")}.tmp`);
59338
+ const tmp = join8(dirname6(file2), `.${process.pid}.${randomBytes2(4).toString("hex")}.tmp`);
59337
59339
  try {
59338
59340
  writeFileSync2(tmp, `${JSON.stringify(value, null, 2)}
59339
59341
  `);
@@ -59346,7 +59348,7 @@ function commitJson(file2, value, rename2) {
59346
59348
  function freshDirectory(pair, paths) {
59347
59349
  mkdirSync4(paths.generationsDir, { recursive: true });
59348
59350
  for (;; ) {
59349
- const dir = join9(paths.generationsDir, `${pair.codexVersion}-${stamp(pair.provenance.installedAt)}-${randomBytes2(3).toString("hex")}`);
59351
+ const dir = join8(paths.generationsDir, `${pair.codexVersion}-${stamp(pair.provenance.installedAt)}-${randomBytes2(3).toString("hex")}`);
59350
59352
  if (existsSync5(dir))
59351
59353
  continue;
59352
59354
  mkdirSync4(dir);
@@ -59360,10 +59362,10 @@ function createGeneration(pair, paths, rename2 = renameSync2) {
59360
59362
  for (const name of GENERATION_EXECUTABLES)
59361
59363
  copyInto(pair.directory, dir, name, 493, pair.provenance.executables[name]);
59362
59364
  for (const name of GENERATION_LEGAL_FILES) {
59363
- if (existsSync5(join9(pair.directory, name)))
59365
+ if (existsSync5(join8(pair.directory, name)))
59364
59366
  copyInto(pair.directory, dir, name, 420);
59365
59367
  }
59366
- commitJson(join9(dir, INSTALLATION_FILE), installationRecord(pair), rename2);
59368
+ commitJson(join8(dir, INSTALLATION_FILE), installationRecord(pair), rename2);
59367
59369
  } catch (e) {
59368
59370
  rmSync(dir, { recursive: true, force: true });
59369
59371
  throw e;
@@ -59371,11 +59373,11 @@ function createGeneration(pair, paths, rename2 = renameSync2) {
59371
59373
  return dir;
59372
59374
  }
59373
59375
  function isGenerationDir(dir) {
59374
- return existsSync5(join9(dir, INSTALLATION_FILE)) && existsSync5(join9(dir, "codex"));
59376
+ return existsSync5(join8(dir, INSTALLATION_FILE)) && existsSync5(join8(dir, "codex"));
59375
59377
  }
59376
59378
  function listGenerations(paths) {
59377
59379
  try {
59378
- return readdirSync2(paths.generationsDir).map((name) => join9(paths.generationsDir, name)).sort();
59380
+ return readdirSync2(paths.generationsDir).map((name) => join8(paths.generationsDir, name)).sort();
59379
59381
  } catch {
59380
59382
  return [];
59381
59383
  }
@@ -59408,7 +59410,7 @@ function activeGeneration(paths) {
59408
59410
  const target = readPointer(paths);
59409
59411
  if (target === null)
59410
59412
  return null;
59411
- const abs = isAbsolute(target) ? target : resolve2(dirname7(paths.currentGeneration), target);
59413
+ const abs = isAbsolute(target) ? target : resolve2(dirname6(paths.currentGeneration), target);
59412
59414
  if (!insideGenerationsRoot(paths, abs))
59413
59415
  return null;
59414
59416
  try {
@@ -59433,6 +59435,7 @@ var RecordSchema = exports_external.object({
59433
59435
  source: exports_external.enum(["prebuilt", "compiled"]),
59434
59436
  cxVersion: exports_external.string(),
59435
59437
  platform: exports_external.string(),
59438
+ patchVersion: exports_external.number().int().positive().max(Number.MAX_SAFE_INTEGER).optional(),
59436
59439
  patchSha256: exports_external.string().regex(HEX64, "patchSha256 must be 64 lowercase hex chars"),
59437
59440
  upstreamCommit: exports_external.string().regex(HEX40, "upstreamCommit must be 40 lowercase hex chars"),
59438
59441
  sourceCommit: exports_external.string().regex(HEX40, "sourceCommit must be 40 lowercase hex chars").nullable(),
@@ -59459,6 +59462,8 @@ function checkedRecord(v) {
59459
59462
  codexVersion: parsed.data.codexVersion,
59460
59463
  platform: provenance.platform
59461
59464
  });
59465
+ if (provenance.patchVersion !== manifest.patchVersion)
59466
+ return null;
59462
59467
  const release = { ...provenance.release, manifest };
59463
59468
  return { ...parsed.data, provenance: { ...provenance, release } };
59464
59469
  } catch {
@@ -59470,7 +59475,7 @@ function readInstallation(paths) {
59470
59475
  if (dir === null)
59471
59476
  return null;
59472
59477
  try {
59473
- const raw = JSON.parse(readFileSync5(join9(dir, INSTALLATION_FILE), "utf8"));
59478
+ const raw = JSON.parse(readFileSync5(join8(dir, INSTALLATION_FILE), "utf8"));
59474
59479
  return checkedRecord(raw);
59475
59480
  } catch {
59476
59481
  return null;
@@ -59479,7 +59484,7 @@ function readInstallation(paths) {
59479
59484
 
59480
59485
  // src/distribution/archive.ts
59481
59486
  import { createReadStream, createWriteStream } from "node:fs";
59482
- import { join as join10 } from "node:path";
59487
+ import { join as join9 } from "node:path";
59483
59488
  import { createGunzip } from "node:zlib";
59484
59489
 
59485
59490
  // node_modules/tar/dist/esm/index.min.js
@@ -62754,7 +62759,7 @@ function rejectionReason(entry, seen, budget) {
62754
62759
  function writeEntry(entry, staging) {
62755
62760
  const name = entry.path;
62756
62761
  const mode = isExecutable(name) ? EXECUTABLE_MODE : LEGAL_MODE;
62757
- const sink = createWriteStream(join10(staging, name), { mode, flags: "wx" });
62762
+ const sink = createWriteStream(join9(staging, name), { mode, flags: "wx" });
62758
62763
  const done = new Promise((resolve3, reject2) => {
62759
62764
  sink.on("error", reject2);
62760
62765
  entry.on("error", reject2);
@@ -62840,7 +62845,7 @@ async function extractArchive(archivePath, staging) {
62840
62845
  import { createHash as createHash3 } from "node:crypto";
62841
62846
  import { createReadStream as createReadStream2, existsSync as existsSync6, renameSync as renameSync3 } from "node:fs";
62842
62847
  import { open as open2 } from "node:fs/promises";
62843
- import { dirname as dirname8, join as join11 } from "node:path";
62848
+ import { dirname as dirname7, join as join10 } from "node:path";
62844
62849
  var PUBLIC_BASE = "https://github.com/adrijshikhar/cxstatusline/releases/download";
62845
62850
  var REPO = "adrijshikhar/cxstatusline";
62846
62851
  var MAX_REDIRECTS = 5;
@@ -63086,7 +63091,7 @@ async function ghDownload(ctx, tag, asset, dest, maxBytes) {
63086
63091
  if (ctx.which("gh") === null) {
63087
63092
  throw new GhMissingError(`${asset} is not public for release ${tag} and GitHub CLI (gh) is not installed`);
63088
63093
  }
63089
- const targetDir = dirname8(dest);
63094
+ const targetDir = dirname7(dest);
63090
63095
  const result2 = ctx.run("gh", ["release", "download", tag, "--repo", REPO, "--pattern", asset, "--dir", targetDir], { timeoutMs: GH_TIMEOUT_MS });
63091
63096
  if (result2.status !== 0) {
63092
63097
  const detail = sanitize(result2.stderr || result2.stdout);
@@ -63095,7 +63100,7 @@ async function ghDownload(ctx, tag, asset, dest, maxBytes) {
63095
63100
  }
63096
63101
  throw new ReleaseUnavailableError(`release ${tag} not found or access denied: ${detail}`);
63097
63102
  }
63098
- const downloadedFile = join11(targetDir, asset);
63103
+ const downloadedFile = join10(targetDir, asset);
63099
63104
  if (!existsSync6(downloadedFile) && !existsSync6(dest)) {
63100
63105
  throw new ReleaseUnavailableError(`release ${tag} not found or access denied: gh downloaded no ${asset}`);
63101
63106
  }
@@ -63124,7 +63129,7 @@ function sameDigest(a, b2) {
63124
63129
  }
63125
63130
  function privateTemp(ctx, prefix) {
63126
63131
  mkdirSync5(ctx.paths.libexecDir, { recursive: true });
63127
- const dir = mkdtempSync(join12(ctx.paths.libexecDir, prefix));
63132
+ const dir = mkdtempSync(join11(ctx.paths.libexecDir, prefix));
63128
63133
  chmodSync2(dir, 448);
63129
63134
  return dir;
63130
63135
  }
@@ -63142,7 +63147,7 @@ function unchangedPair(ctx, manifest, artifact, tag) {
63142
63147
  if (!release || release.tag !== tag || release.archiveSha256 !== artifact.sha256)
63143
63148
  return null;
63144
63149
  const installed = release.manifest;
63145
- const identical = record2.codexVersion === manifest.codexVersion && record2.provenance.cxVersion === manifest.cxVersion && record2.provenance.platform === artifact.platform && 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 && 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;
63146
63151
  if (!identical)
63147
63152
  return null;
63148
63153
  const directory = activeGeneration(ctx.paths);
@@ -63150,7 +63155,7 @@ function unchangedPair(ctx, manifest, artifact, tag) {
63150
63155
  return null;
63151
63156
  for (const name of ARTIFACT_FILES) {
63152
63157
  try {
63153
- if (!sameDigest(digestOf2(join12(directory, name)), artifact.files[name]))
63158
+ if (!sameDigest(digestOf2(join11(directory, name)), artifact.files[name]))
63154
63159
  return null;
63155
63160
  } catch {
63156
63161
  return null;
@@ -63161,7 +63166,7 @@ function unchangedPair(ctx, manifest, artifact, tag) {
63161
63166
  function verifyStaged(staging, artifact) {
63162
63167
  const digests = {};
63163
63168
  for (const name of ARTIFACT_FILES) {
63164
- const got = digestOf2(join12(staging, name));
63169
+ const got = digestOf2(join11(staging, name));
63165
63170
  if (!sameDigest(got, artifact.files[name])) {
63166
63171
  throw new Error(`staged ${name} does not match the release manifest sha256`);
63167
63172
  }
@@ -63173,7 +63178,7 @@ function verifyStaged(staging, artifact) {
63173
63178
  };
63174
63179
  }
63175
63180
  function probeVersion(ctx, staging, codexVersion) {
63176
- const probe = ctx.run(join12(staging, "codex"), ["--version"], { timeoutMs: PROBE_TIMEOUT_MS });
63181
+ const probe = ctx.run(join11(staging, "codex"), ["--version"], { timeoutMs: PROBE_TIMEOUT_MS });
63177
63182
  const reported = sanitize((probe.stdout || probe.stderr).slice(0, 512));
63178
63183
  if (probe.status !== 0 || reported !== `codex-cli ${codexVersion}`) {
63179
63184
  throw new Error(`staged codex reported version "${reported}" instead of "codex-cli ${codexVersion}"`);
@@ -63189,6 +63194,7 @@ function stagedPair(ctx, staging, manifest, artifact, tag) {
63189
63194
  source: "prebuilt",
63190
63195
  cxVersion: manifest.cxVersion ?? VERSION,
63191
63196
  platform: artifact.platform,
63197
+ patchVersion: manifest.patchVersion,
63192
63198
  patchSha256: manifest.patchSha256,
63193
63199
  upstreamCommit: manifest.upstreamCommit,
63194
63200
  sourceCommit: manifest.sourceCommit,
@@ -63214,8 +63220,8 @@ function moveFile(src, dst) {
63214
63220
  async function stageArchive(ctx, download, manifest, artifact, tag, opts) {
63215
63221
  const cacheDir = ctx.paths.downloadCacheDir;
63216
63222
  mkdirSync5(cacheDir, { recursive: true });
63217
- const partFile = join12(cacheDir, `${tag}-${artifact.filename}.part`);
63218
- const archive = join12(download, artifact.filename);
63223
+ const partFile = join11(cacheDir, `${tag}-${artifact.filename}.part`);
63224
+ const archive = join11(download, artifact.filename);
63219
63225
  opts.onStatus?.("download", `Downloading prebuilt archive (${artifact.filename})...`);
63220
63226
  const got = await downloadAsset(ctx, tag, artifact.filename, partFile, ARCHIVE_MAX_BYTES, opts);
63221
63227
  if (got.sha256 !== artifact.sha256 || got.size !== artifact.size) {
@@ -63241,7 +63247,7 @@ async function preparePrebuilt(ctx, expected, opts = {}) {
63241
63247
  opts.onStatus?.("manifest", `Checking release ${tag} for ${expected.platform}...`);
63242
63248
  const download = privateTemp(ctx, "download-");
63243
63249
  try {
63244
- const manifestFile = join12(download, MANIFEST_ASSET);
63250
+ const manifestFile = join11(download, MANIFEST_ASSET);
63245
63251
  await downloadAsset(ctx, tag, MANIFEST_ASSET, manifestFile, MANIFEST_MAX_BYTES, opts);
63246
63252
  const manifest = validateManifest(JSON.parse(readFileSync6(manifestFile, "utf8")), expected);
63247
63253
  const artifact = artifactFor(manifest, expected);
@@ -63264,15 +63270,21 @@ async function fetchPublishedPrebuiltVersions(fetchFn, repo = "adrijshikhar/cxst
63264
63270
  if (process.env.GITHUB_TOKEN) {
63265
63271
  headers.authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
63266
63272
  }
63267
- const res = await fetcher(`https://api.github.com/repos/${repo}/releases?per_page=100`, {
63268
- headers,
63269
- signal: AbortSignal.timeout(5000)
63270
- });
63271
- if (!res.ok)
63272
- return [];
63273
- const data = await res.json();
63274
- if (!Array.isArray(data))
63275
- return [];
63273
+ const data = [];
63274
+ for (let page = 1;; page += 1) {
63275
+ const res = await fetcher(`https://api.github.com/repos/${repo}/releases?per_page=100&page=${page}`, {
63276
+ headers,
63277
+ signal: AbortSignal.timeout(5000)
63278
+ });
63279
+ if (!res.ok)
63280
+ return [];
63281
+ const result2 = await res.json();
63282
+ if (!Array.isArray(result2))
63283
+ return [];
63284
+ data.push(...result2);
63285
+ if (result2.length < 100)
63286
+ break;
63287
+ }
63276
63288
  const versions2 = new Set;
63277
63289
  for (const item of data) {
63278
63290
  if (typeof item === "object" && item !== null) {
@@ -63345,7 +63357,8 @@ var ArtifactSchema = exports_external.object({
63345
63357
  files: FilesSchema
63346
63358
  }).strict();
63347
63359
  var ManifestShapeSchema = exports_external.object({
63348
- schema: exports_external.literal(1),
63360
+ schema: exports_external.union([exports_external.literal(1), exports_external.literal(2)]),
63361
+ patchVersion: exports_external.number().refine(safePositiveInt).optional(),
63349
63362
  cxVersion: exports_external.string().optional(),
63350
63363
  codexVersion: exports_external.string(),
63351
63364
  upstreamTag: exports_external.string(),
@@ -63375,6 +63388,10 @@ function checkArtifacts(m2, expected) {
63375
63388
  return null;
63376
63389
  }
63377
63390
  function checkBusinessRules(m2, expected) {
63391
+ if (m2.schema === 2 && m2.patchVersion === undefined)
63392
+ return "patchVersion is required for schema 2";
63393
+ if (m2.schema === 1 && m2.patchVersion !== undefined)
63394
+ return "patchVersion requires schema 2";
63378
63395
  if (m2.cxVersion !== undefined && !isStableVersion(m2.cxVersion)) {
63379
63396
  return "cxVersion is not a valid semver";
63380
63397
  }
@@ -63383,7 +63400,9 @@ function checkBusinessRules(m2, expected) {
63383
63400
  }
63384
63401
  if (m2.upstreamTag !== `rust-v${m2.codexVersion}`)
63385
63402
  return "upstreamTag does not match codexVersion";
63386
- if (m2.patchFile !== `codex-${m2.codexVersion}.patch`)
63403
+ if (m2.schema === 2 && !/^[a-zA-Z0-9][a-zA-Z0-9._-]*\.patch$/.test(m2.patchFile))
63404
+ return "patchFile must be a patch basename";
63405
+ if (m2.schema === 1 && m2.patchFile !== `codex-${m2.codexVersion}.patch`)
63387
63406
  return "patchFile does not match codexVersion";
63388
63407
  if (Number.isNaN(Date.parse(m2.createdAt)))
63389
63408
  return "createdAt is not a valid timestamp";
@@ -63411,82 +63430,6 @@ function validateManifest(raw, expected) {
63411
63430
  return structural.data;
63412
63431
  }
63413
63432
 
63414
- // src/codex/upstream.ts
63415
- import { accessSync as accessSync2, constants as constants3, lstatSync as lstatSync3, readlinkSync as readlinkSync2, realpathSync as realpathSync3, statSync as statSync2 } from "node:fs";
63416
- import { dirname as dirname9, isAbsolute as isAbsolute2, join as join13, resolve as resolve3 } from "node:path";
63417
- function isExecutable2(p2) {
63418
- try {
63419
- accessSync2(p2, constants3.X_OK);
63420
- return statSync2(p2).isFile();
63421
- } catch {
63422
- return false;
63423
- }
63424
- }
63425
- function isManaged(p2, paths, isOurWrapper) {
63426
- if (resolve3(p2) === resolve3(paths.patchedBin) || isOurWrapper(p2))
63427
- return true;
63428
- try {
63429
- return realpathSync3(p2) === realpathSync3(paths.patchedBin);
63430
- } catch {
63431
- return false;
63432
- }
63433
- }
63434
- function inspectLauncher(paths, isOurWrapper) {
63435
- let st2;
63436
- try {
63437
- st2 = lstatSync3(paths.wrapperPath);
63438
- } catch {
63439
- return null;
63440
- }
63441
- if (st2.isSymbolicLink()) {
63442
- const raw = readlinkSync2(paths.wrapperPath);
63443
- const target = isAbsolute2(raw) ? raw : resolve3(dirname9(paths.wrapperPath), raw);
63444
- if (isManaged(target, paths, isOurWrapper))
63445
- return null;
63446
- return { kind: "found", bin: target, launcher_restore: { kind: "symlink", target } };
63447
- }
63448
- if (isOurWrapper(paths.wrapperPath))
63449
- return null;
63450
- return { kind: "foreign", path: paths.wrapperPath };
63451
- }
63452
- function walkPath(paths, env3, isOurWrapper) {
63453
- for (const dir of (env3.PATH ?? "").split(":").filter(Boolean)) {
63454
- if (resolve3(dir) === resolve3(paths.binDir))
63455
- continue;
63456
- const candidate = join13(dir, "codex");
63457
- if (isExecutable2(candidate) && !isManaged(candidate, paths, isOurWrapper))
63458
- return candidate;
63459
- }
63460
- return null;
63461
- }
63462
- function resolveUpstream(paths, env3, isOurWrapper, savedBin) {
63463
- const launcher = inspectLauncher(paths, isOurWrapper);
63464
- if (launcher)
63465
- return launcher;
63466
- const current = walkPath(paths, env3, isOurWrapper);
63467
- const bin = current ?? (savedBin && isExecutable2(savedBin) && !isManaged(savedBin, paths, isOurWrapper) ? savedBin : null);
63468
- return bin ? { kind: "found", bin, launcher_restore: { kind: "none" } } : { kind: "not-found" };
63469
- }
63470
- function describeLookup(l) {
63471
- switch (l.kind) {
63472
- case "found":
63473
- return l.bin;
63474
- case "foreign":
63475
- return `${l.path} is a real file we did not write; refusing to overwrite it`;
63476
- case "not-found":
63477
- return "no upstream Codex found (nothing named codex on PATH outside ~/.local/bin, and the launcher there is not a symlink)";
63478
- }
63479
- }
63480
- function readUpstreamVersion(bin, run) {
63481
- const r = run(bin, ["--version"]);
63482
- if (r.status !== 0)
63483
- return null;
63484
- return parseCodexVersionOutput(r.stdout);
63485
- }
63486
- function preserveLauncherRestore(recorded, found) {
63487
- return found.kind === "symlink" ? found : recorded ?? found;
63488
- }
63489
-
63490
63433
  // src/hook/install.ts
63491
63434
  import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
63492
63435
 
@@ -63628,94 +63571,322 @@ function writeState(file2, state) {
63628
63571
  writeFileAtomic(`${file2}${BACKUP_SUFFIX}`, text);
63629
63572
  }
63630
63573
 
63631
- // src/ui/prompt-version.ts
63632
- import { createInterface } from "node:readline";
63633
- async function promptCodexVersion(options) {
63634
- const { supportedVersions, prebuiltVersions, isTTY = false, say = (s3) => console.log(s3) } = options;
63635
- if (supportedVersions.length === 0) {
63636
- throw new Error("No supported Codex versions available.");
63637
- }
63638
- let defaultVersion;
63639
- if (options.defaultVersion && supportedVersions.includes(options.defaultVersion)) {
63640
- defaultVersion = options.defaultVersion;
63641
- } else if (prebuiltVersions && prebuiltVersions.length > 0) {
63642
- defaultVersion = supportedVersions.find((v2) => prebuiltVersions.includes(v2)) ?? supportedVersions[0];
63643
- } else {
63644
- defaultVersion = supportedVersions[0];
63645
- }
63646
- if (!isTTY) {
63647
- const isSourceOnly = Boolean(prebuiltVersions && !prebuiltVersions.includes(defaultVersion));
63648
- return { version: defaultVersion, compile: isSourceOnly };
63649
- }
63650
- const defaultIndex = supportedVersions.indexOf(defaultVersion) + 1;
63651
- say(`
63652
- Select Codex version to install:`);
63653
- supportedVersions.forEach((v2, idx) => {
63654
- const isDef = v2 === defaultVersion;
63655
- let tag = "";
63656
- if (prebuiltVersions) {
63657
- tag = prebuiltVersions.includes(v2) ? " [prebuilt available]" : " [compile from source - prebuilt pending]";
63658
- }
63659
- say(` ${idx + 1}) ${v2}${tag}${isDef ? " (recommended / default)" : ""}`);
63660
- });
63661
- const askFn = options.ask ?? defaultAsk;
63662
- while (true) {
63663
- const raw = (await askFn(`Enter choice [1-${supportedVersions.length}] (default ${defaultIndex}): `)).trim();
63664
- let selectedVersion = null;
63665
- if (raw === "") {
63666
- selectedVersion = defaultVersion;
63667
- } else {
63668
- const num2 = Number.parseInt(raw, 10);
63669
- if (!Number.isNaN(num2) && num2 >= 1 && num2 <= supportedVersions.length) {
63670
- selectedVersion = supportedVersions[num2 - 1];
63671
- } else if (supportedVersions.includes(raw)) {
63672
- selectedVersion = raw;
63673
- }
63674
- }
63675
- if (!selectedVersion) {
63676
- say(`Invalid selection "${raw}". Please enter a number between 1 and ${supportedVersions.length}.`);
63677
- continue;
63574
+ // src/ui/UpdatePicker.tsx
63575
+ var import_react38 = __toESM(require_react(), 1);
63576
+
63577
+ // src/tui/components/List.tsx
63578
+ var import_react35 = __toESM(require_react(), 1);
63579
+ var jsx_dev_runtime10 = __toESM(require_jsx_dev_runtime(), 1);
63580
+ function List({
63581
+ items,
63582
+ onSelect,
63583
+ onSelectionChange,
63584
+ initialSelection = 0,
63585
+ showBackButton = false,
63586
+ color,
63587
+ wrapNavigation = true,
63588
+ maxVisibleItems,
63589
+ ...boxProps
63590
+ }) {
63591
+ const [selectedIndex, setSelectedIndex] = import_react35.useState(initialSelection);
63592
+ const latestOnSelectionChange = import_react35.useRef(onSelectionChange);
63593
+ const displayedItems = import_react35.useMemo(() => showBackButton ? [...items, "-", { label: "← Back", value: "back" }] : [...items], [items, showBackButton]);
63594
+ const selectableItems = displayedItems.filter((item) => item !== "-" && !item.disabled);
63595
+ const selectedItem = selectableItems[selectedIndex];
63596
+ const firstVisible = maxVisibleItems && selectableItems.length > maxVisibleItems ? Math.max(0, Math.min(selectedIndex, selectableItems.length - maxVisibleItems)) : 0;
63597
+ const visibleItems = maxVisibleItems ? selectableItems.slice(firstVisible, firstVisible + maxVisibleItems) : displayedItems;
63598
+ import_react35.useEffect(() => {
63599
+ latestOnSelectionChange.current = onSelectionChange;
63600
+ }, [onSelectionChange]);
63601
+ import_react35.useEffect(() => {
63602
+ setSelectedIndex(Math.min(initialSelection, Math.max(0, selectableItems.length - 1)));
63603
+ }, [initialSelection, selectableItems.length]);
63604
+ import_react35.useEffect(() => {
63605
+ if (selectedItem)
63606
+ latestOnSelectionChange.current?.(selectedItem.value, selectedIndex);
63607
+ }, [selectedIndex, selectedItem]);
63608
+ use_input_default((_2, key) => {
63609
+ if (!selectableItems.length)
63610
+ return;
63611
+ if (key.upArrow) {
63612
+ setSelectedIndex((current) => current === 0 ? wrapNavigation ? selectableItems.length - 1 : 0 : current - 1);
63613
+ return;
63678
63614
  }
63679
- const hasPrebuilt = !prebuiltVersions || prebuiltVersions.includes(selectedVersion);
63680
- if (!hasPrebuilt) {
63681
- const confirm = (await askFn(`No prebuilt binary is published for Codex ${selectedVersion} yet. Would you like to compile from source instead? [y/N]: `)).trim().toLowerCase();
63682
- if (confirm === "y" || confirm === "yes") {
63683
- return { version: selectedVersion, compile: true };
63684
- }
63685
- say("Please select a version with prebuilt binaries available, or run with --compile.");
63686
- continue;
63615
+ if (key.downArrow) {
63616
+ setSelectedIndex((current) => current === selectableItems.length - 1 ? wrapNavigation ? 0 : selectableItems.length - 1 : current + 1);
63617
+ return;
63687
63618
  }
63688
- return { version: selectedVersion, compile: false };
63619
+ if (key.return && selectedItem)
63620
+ onSelect(selectedItem.value, selectedIndex);
63621
+ });
63622
+ return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
63623
+ flexDirection: "column",
63624
+ ...boxProps,
63625
+ children: [
63626
+ maxVisibleItems && firstVisible > 0 && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
63627
+ dimColor: true,
63628
+ children: "↑ more"
63629
+ }, undefined, false, undefined, this),
63630
+ visibleItems.map((item, index) => {
63631
+ if (item === "-")
63632
+ return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
63633
+ children: " "
63634
+ }, `separator-${index}`, false, undefined, this);
63635
+ return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(ListItem, {
63636
+ isSelected: item === selectedItem,
63637
+ ...color && { color },
63638
+ ...item.disabled !== undefined && { disabled: item.disabled },
63639
+ ...item.props,
63640
+ children: [
63641
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
63642
+ children: item.label
63643
+ }, undefined, false, undefined, this),
63644
+ item.sublabel && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
63645
+ dimColor: item !== selectedItem,
63646
+ children: ` ${item.sublabel}`
63647
+ }, undefined, false, undefined, this)
63648
+ ]
63649
+ }, item.value, true, undefined, this);
63650
+ }),
63651
+ maxVisibleItems && firstVisible + visibleItems.length < selectableItems.length && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
63652
+ dimColor: true,
63653
+ children: "↓ more"
63654
+ }, undefined, false, undefined, this),
63655
+ selectedItem?.description && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
63656
+ marginTop: 1,
63657
+ paddingLeft: 2,
63658
+ children: /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
63659
+ dimColor: true,
63660
+ wrap: "wrap",
63661
+ children: selectedItem.description
63662
+ }, undefined, false, undefined, this)
63663
+ }, undefined, false, undefined, this)
63664
+ ]
63665
+ }, undefined, true, undefined, this);
63666
+ }
63667
+ function ListItem({ children, isSelected, color = "green", disabled, ...boxProps }) {
63668
+ return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
63669
+ ...boxProps,
63670
+ children: /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
63671
+ ...isSelected && { color },
63672
+ ...disabled && { dimColor: true },
63673
+ children: [
63674
+ isSelected ? "▶ " : " ",
63675
+ children
63676
+ ]
63677
+ }, undefined, true, undefined, this)
63678
+ }, undefined, false, undefined, this);
63679
+ }
63680
+
63681
+ // src/ui/prompt.ts
63682
+ var import_react37 = __toESM(require_react(), 1);
63683
+
63684
+ // src/ui/terminal-size.ts
63685
+ var import_react36 = __toESM(require_react(), 1);
63686
+ var MIN_MENU_COLUMNS = 40;
63687
+ var MIN_MENU_ROWS = 20;
63688
+ function isUsableMenuSize(columns, rows) {
63689
+ return columns >= MIN_MENU_COLUMNS && rows >= MIN_MENU_ROWS;
63690
+ }
63691
+ function menuItemsForRows(rows) {
63692
+ return Math.max(1, Math.min(8, rows - 13));
63693
+ }
63694
+ function useTerminalSize() {
63695
+ const { stdout } = use_stdout_default();
63696
+ const [size2, setSize] = import_react36.useState({ columns: stdout.columns || 80, rows: stdout.rows || 24 });
63697
+ import_react36.useEffect(() => {
63698
+ const update2 = () => setSize({ columns: stdout.columns || 80, rows: stdout.rows || 24 });
63699
+ stdout.on("resize", update2);
63700
+ return () => {
63701
+ stdout.off("resize", update2);
63702
+ };
63703
+ }, [stdout]);
63704
+ return { ...size2, usable: isUsableMenuSize(size2.columns, size2.rows), maxVisibleItems: menuItemsForRows(size2.rows) };
63705
+ }
63706
+
63707
+ // src/ui/prompt.ts
63708
+ async function prompt(element, cancelled) {
63709
+ if (!isUsableMenuSize(process.stdout.columns ?? 0, process.stdout.rows ?? 0)) {
63710
+ throw new Error(`Terminal must be at least ${MIN_MENU_COLUMNS} columns × ${MIN_MENU_ROWS} rows for an interactive menu. Resize it or rerun with explicit options.`);
63711
+ }
63712
+ let resolveSelection;
63713
+ const selection = new Promise((resolve3) => {
63714
+ resolveSelection = resolve3;
63715
+ });
63716
+ const instance = render_default(element(resolveSelection), { exitOnCtrlC: false, preserveScrollback: true, isCI: false });
63717
+ try {
63718
+ return await Promise.race([selection, instance.waitUntilExit().then(() => cancelled)]);
63719
+ } finally {
63720
+ instance.rerender(import_react37.createElement(Text, {}, ""));
63721
+ instance.clear();
63722
+ instance.unmount();
63723
+ instance.cleanup();
63689
63724
  }
63690
63725
  }
63691
- function defaultAsk(question) {
63692
- const rl = createInterface({
63693
- input: process.stdin,
63694
- output: process.stdout
63726
+
63727
+ // src/ui/UpdatePicker.tsx
63728
+ var jsx_dev_runtime11 = __toESM(require_jsx_dev_runtime(), 1);
63729
+ function UpdatePicker({ latest, highestAvailable, onSelect }) {
63730
+ const { usable, maxVisibleItems } = useTerminalSize();
63731
+ const [selectedIndex, setSelectedIndex] = import_react38.useState(highestAvailable ? 0 : 1);
63732
+ use_input_default((input2, key) => {
63733
+ if (key.escape || key.ctrl && input2 === "c")
63734
+ onSelect("cancel");
63695
63735
  });
63696
- return new Promise((resolve4) => {
63697
- rl.question(question, (answer) => {
63698
- rl.close();
63699
- resolve4(answer);
63736
+ if (!usable)
63737
+ return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
63738
+ flexDirection: "column",
63739
+ marginY: 1,
63740
+ children: [
63741
+ /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
63742
+ children: "Resize terminal to at least 40 columns × 20 rows to continue."
63743
+ }, undefined, false, undefined, this),
63744
+ /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
63745
+ dimColor: true,
63746
+ children: "Esc/Ctrl+C cancel"
63747
+ }, undefined, false, undefined, this)
63748
+ ]
63749
+ }, undefined, true, undefined, this);
63750
+ const items = [];
63751
+ if (highestAvailable)
63752
+ items.push({
63753
+ label: `Install prebuilt Codex ${highestAvailable}`,
63754
+ sublabel: "· recommended",
63755
+ value: "prebuilt",
63756
+ description: "Downloads a verified prebuilt. No Rust toolchain needed."
63700
63757
  });
63701
- });
63758
+ items.push({
63759
+ label: `Compile Codex ${latest} from source`,
63760
+ value: "compile",
63761
+ description: "Requires Rust, at least 20 GiB free, and may take tens of minutes."
63762
+ }, { label: "Cancel", value: "cancel" });
63763
+ return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
63764
+ flexDirection: "column",
63765
+ marginY: 1,
63766
+ children: [
63767
+ /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
63768
+ bold: true,
63769
+ children: "How would you like to proceed?"
63770
+ }, undefined, false, undefined, this),
63771
+ /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(List, {
63772
+ items,
63773
+ marginTop: 1,
63774
+ maxVisibleItems,
63775
+ initialSelection: selectedIndex,
63776
+ onSelectionChange: (_2, index) => setSelectedIndex(index),
63777
+ onSelect: (value) => {
63778
+ if (value !== "back")
63779
+ onSelect(value);
63780
+ }
63781
+ }, undefined, false, undefined, this),
63782
+ /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
63783
+ marginTop: 1,
63784
+ children: /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
63785
+ dimColor: true,
63786
+ children: "↑/↓ navigate · Enter select · Esc/Ctrl+C cancel"
63787
+ }, undefined, false, undefined, this)
63788
+ }, undefined, false, undefined, this)
63789
+ ]
63790
+ }, undefined, true, undefined, this);
63791
+ }
63792
+ function promptUpdate(options) {
63793
+ return prompt((onSelect) => /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(UpdatePicker, {
63794
+ ...options,
63795
+ onSelect
63796
+ }, undefined, false, undefined, this), "cancel");
63702
63797
  }
63703
63798
 
63704
63799
  // src/patch/acquire.ts
63705
63800
  import { rmSync as rmSync5 } from "node:fs";
63706
63801
 
63707
- // src/patch/compile.ts
63708
- import { chmodSync as chmodSync3, copyFileSync as copyFileSync3, mkdirSync as mkdirSync6, mkdtempSync as mkdtempSync2, readFileSync as readFileSync10, rmSync as rmSync3, statSync as statSync4 } from "node:fs";
63709
- import { createHash as createHash5 } from "node:crypto";
63710
- import { join as join16 } from "node:path";
63711
-
63712
- // src/patch/build.ts
63713
- import { existsSync as existsSync10, lstatSync as lstatSync4, readFileSync as readFileSync9, statSync as statSync3 } from "node:fs";
63714
- import { join as join15 } from "node:path";
63715
-
63716
- // src/patch/v8.ts
63717
- import { existsSync as existsSync9 } from "node:fs";
63802
+ // src/codex/upstream.ts
63803
+ import { accessSync as accessSync2, constants as constants3, lstatSync as lstatSync3, readlinkSync as readlinkSync2, realpathSync as realpathSync3, statSync as statSync2 } from "node:fs";
63804
+ import { dirname as dirname8, isAbsolute as isAbsolute2, join as join12, resolve as resolve3 } from "node:path";
63805
+ function isExecutable2(p2) {
63806
+ try {
63807
+ accessSync2(p2, constants3.X_OK);
63808
+ return statSync2(p2).isFile();
63809
+ } catch {
63810
+ return false;
63811
+ }
63812
+ }
63813
+ function isManaged(p2, paths, isOurWrapper) {
63814
+ if (resolve3(p2) === resolve3(paths.patchedBin) || isOurWrapper(p2))
63815
+ return true;
63816
+ try {
63817
+ return realpathSync3(p2) === realpathSync3(paths.patchedBin);
63818
+ } catch {
63819
+ return false;
63820
+ }
63821
+ }
63822
+ function inspectLauncher(paths, isOurWrapper) {
63823
+ let st2;
63824
+ try {
63825
+ st2 = lstatSync3(paths.wrapperPath);
63826
+ } catch {
63827
+ return null;
63828
+ }
63829
+ if (st2.isSymbolicLink()) {
63830
+ const raw = readlinkSync2(paths.wrapperPath);
63831
+ const target = isAbsolute2(raw) ? raw : resolve3(dirname8(paths.wrapperPath), raw);
63832
+ if (isManaged(target, paths, isOurWrapper))
63833
+ return null;
63834
+ return { kind: "found", bin: target, launcher_restore: { kind: "symlink", target } };
63835
+ }
63836
+ if (isOurWrapper(paths.wrapperPath))
63837
+ return null;
63838
+ return { kind: "foreign", path: paths.wrapperPath };
63839
+ }
63840
+ function walkPath(paths, env3, isOurWrapper) {
63841
+ for (const dir of (env3.PATH ?? "").split(":").filter(Boolean)) {
63842
+ if (resolve3(dir) === resolve3(paths.binDir))
63843
+ continue;
63844
+ const candidate = join12(dir, "codex");
63845
+ if (isExecutable2(candidate) && !isManaged(candidate, paths, isOurWrapper))
63846
+ return candidate;
63847
+ }
63848
+ return null;
63849
+ }
63850
+ function resolveUpstream(paths, env3, isOurWrapper, savedBin) {
63851
+ const launcher = inspectLauncher(paths, isOurWrapper);
63852
+ if (launcher)
63853
+ return launcher;
63854
+ const current = walkPath(paths, env3, isOurWrapper);
63855
+ const bin = current ?? (savedBin && isExecutable2(savedBin) && !isManaged(savedBin, paths, isOurWrapper) ? savedBin : null);
63856
+ return bin ? { kind: "found", bin, launcher_restore: { kind: "none" } } : { kind: "not-found" };
63857
+ }
63858
+ function describeLookup(l) {
63859
+ switch (l.kind) {
63860
+ case "found":
63861
+ return l.bin;
63862
+ case "foreign":
63863
+ return `${l.path} is a real file we did not write; refusing to overwrite it`;
63864
+ case "not-found":
63865
+ return "no upstream Codex found (nothing named codex on PATH outside ~/.local/bin, and the launcher there is not a symlink)";
63866
+ }
63867
+ }
63868
+ function readUpstreamVersion(bin, run) {
63869
+ const r = run(bin, ["--version"]);
63870
+ if (r.status !== 0)
63871
+ return null;
63872
+ return parseCodexVersionOutput(r.stdout);
63873
+ }
63874
+ function preserveLauncherRestore(recorded, found) {
63875
+ return found.kind === "symlink" ? found : recorded ?? found;
63876
+ }
63877
+
63878
+ // src/patch/compile.ts
63879
+ import { chmodSync as chmodSync3, copyFileSync as copyFileSync3, mkdirSync as mkdirSync6, mkdtempSync as mkdtempSync2, readFileSync as readFileSync10, rmSync as rmSync3, statSync as statSync4 } from "node:fs";
63880
+ import { createHash as createHash5 } from "node:crypto";
63881
+ import { join as join15 } from "node:path";
63882
+
63883
+ // src/patch/build.ts
63884
+ import { existsSync as existsSync10, lstatSync as lstatSync4, readFileSync as readFileSync9, statSync as statSync3 } from "node:fs";
63718
63885
  import { join as join14 } from "node:path";
63886
+
63887
+ // src/patch/v8.ts
63888
+ import { existsSync as existsSync9 } from "node:fs";
63889
+ import { join as join13 } from "node:path";
63719
63890
  function defaultV8Target() {
63720
63891
  const isArm = process.arch === "arm64";
63721
63892
  if (process.platform === "darwin")
@@ -63746,7 +63917,7 @@ function resolveV8Env(sourceDir, run, log) {
63746
63917
  RUSTY_V8_SRC_BINDING_PATH: process.env.RUSTY_V8_SRC_BINDING_PATH
63747
63918
  };
63748
63919
  }
63749
- const v8Script = join14(sourceDir, "scripts", "codex_package", "v8.py");
63920
+ const v8Script = join13(sourceDir, "scripts", "codex_package", "v8.py");
63750
63921
  if (!existsSync9(v8Script)) {
63751
63922
  return {};
63752
63923
  }
@@ -63818,9 +63989,9 @@ function headCommit(plan, run) {
63818
63989
  }
63819
63990
  function prepareCheckout(plan, run, log) {
63820
63991
  const git = (step, ...args) => must(step, run, log, "git", ["-C", plan.sourceDir, ...args]);
63821
- if (existsSync10(join15(plan.sourceDir, ".git"))) {
63992
+ if (existsSync10(join14(plan.sourceDir, ".git"))) {
63822
63993
  git("fetch", "fetch", "--tags", "--filter=blob:none", "origin");
63823
- const snapshot = join15(plan.sourceDir, SNAPSHOT);
63994
+ const snapshot = join14(plan.sourceDir, SNAPSHOT);
63824
63995
  const st2 = lstatSync4(snapshot, { throwIfNoEntry: false });
63825
63996
  if (st2) {
63826
63997
  const tracked = run("git", ["-C", plan.sourceDir, "ls-files", "--error-unmatch", "--", SNAPSHOT]);
@@ -63848,7 +64019,7 @@ function buildPatched(plan, run, log, which, onStatus) {
63848
64019
  git("apply --check", "apply", "--index", "--check", plan.patchFile);
63849
64020
  git("apply", "apply", "--index", plan.patchFile);
63850
64021
  onStatus?.("patch-done", `Applied ${patchBase} cleanly`);
63851
- const crateDir = join15(plan.sourceDir, "codex-rs");
64022
+ const crateDir = join14(plan.sourceDir, "codex-rs");
63852
64023
  const v8Env = resolveV8Env(plan.sourceDir, run, log);
63853
64024
  onStatus?.("build", "Compiling release binaries (cargo build --release)... Note: this full compile typically takes 10 to 20 minutes.");
63854
64025
  const buildStart = Date.now();
@@ -63857,7 +64028,7 @@ function buildPatched(plan, run, log, which, onStatus) {
63857
64028
  const buildElapsedStr = buildElapsed >= 60 ? `${Math.floor(buildElapsed / 60)}m ${buildElapsed % 60}s` : `${buildElapsed}s`;
63858
64029
  onStatus?.("build-done", `Release binaries compiled (codex, codex-code-mode-host in ${buildElapsedStr})`);
63859
64030
  const [codex, codexCodeModeHost] = TARGETS.map((name) => {
63860
- const bin = join15(crateDir, "target", "release", name);
64031
+ const bin = join14(crateDir, "target", "release", name);
63861
64032
  if (!existsSync10(bin) || statSync3(bin).size === 0) {
63862
64033
  throw new BuildError("cargo build", `cargo exited 0 but ${bin} is missing or empty`);
63863
64034
  }
@@ -63886,7 +64057,7 @@ function platformLabel() {
63886
64057
  }
63887
64058
  function stage(ctx, built) {
63888
64059
  mkdirSync6(ctx.paths.libexecDir, { recursive: true });
63889
- const directory = mkdtempSync2(join16(ctx.paths.libexecDir, STAGING_PREFIX));
64060
+ const directory = mkdtempSync2(join15(ctx.paths.libexecDir, STAGING_PREFIX));
63890
64061
  chmodSync3(directory, 448);
63891
64062
  const sources = {
63892
64063
  codex: built.codex,
@@ -63895,7 +64066,7 @@ function stage(ctx, built) {
63895
64066
  const executables = {};
63896
64067
  try {
63897
64068
  for (const name of GENERATION_EXECUTABLES) {
63898
- const target = join16(directory, name);
64069
+ const target = join15(directory, name);
63899
64070
  copyFileSync3(sources[name], target);
63900
64071
  chmodSync3(target, 493);
63901
64072
  executables[name] = digestOf3(target);
@@ -63913,7 +64084,7 @@ function stage(ctx, built) {
63913
64084
  };
63914
64085
  }
63915
64086
  function prepareCompiled(ctx, upstream, ref, onStatus) {
63916
- const patchFile = join16(ctx.patchesDir, ref.file);
64087
+ const patchFile = join15(ctx.patchesDir, ref.file);
63917
64088
  const patchSha256 = digestOf3(patchFile).sha256;
63918
64089
  const built = buildPatched({ tag: ref.tag, sourceDir: ctx.paths.sourceDir, patchFile }, ctx.run, ctx.log, ctx.which, onStatus);
63919
64090
  onStatus?.("stage", "Staging generation and verifying binaries...");
@@ -63926,6 +64097,7 @@ function prepareCompiled(ctx, upstream, ref, onStatus) {
63926
64097
  source: "compiled",
63927
64098
  cxVersion: VERSION,
63928
64099
  platform: platformLabel(),
64100
+ patchVersion: ref.patchVersion,
63929
64101
  patchSha256,
63930
64102
  upstreamCommit: built.upstreamCommit,
63931
64103
  sourceCommit: SOURCE_COMMIT,
@@ -63938,7 +64110,7 @@ function prepareCompiled(ctx, upstream, ref, onStatus) {
63938
64110
 
63939
64111
  // src/patch/manifest.ts
63940
64112
  import { readFileSync as readFileSync11 } from "node:fs";
63941
- import { join as join17 } from "node:path";
64113
+ import { join as join16 } from "node:path";
63942
64114
  class ManifestError extends Error {
63943
64115
  name = "ManifestError";
63944
64116
  }
@@ -63957,13 +64129,28 @@ var isCandidate = (c) => {
63957
64129
  return parsed !== null && parsed.pre === null;
63958
64130
  };
63959
64131
  function loadManifest(patchesDir) {
63960
- const file2 = join17(patchesDir, "manifest.json");
64132
+ const file2 = join16(patchesDir, "manifest.json");
63961
64133
  try {
63962
64134
  const raw = JSON.parse(readFileSync11(file2, "utf8"));
63963
64135
  const m2 = raw;
63964
- const ok = typeof m2 === "object" && m2 !== null && m2.version === 1 && typeof m2.tag_prefix === "string" && Array.isArray(m2.patches) && m2.patches.every(isRange) && isCandidate(m2.candidate);
64136
+ const ok = typeof m2 === "object" && m2 !== null && (m2.version === 1 || m2.version === 2) && typeof m2.tag_prefix === "string" && Array.isArray(m2.patches) && m2.patches.every(isRange) && isCandidate(m2.candidate);
63965
64137
  if (!ok)
63966
64138
  throw new ManifestError(`${file2}: manifest is malformed`);
64139
+ if (m2.version === 1 && m2.patches.some((p2) => p2.patchVersion !== undefined)) {
64140
+ throw new ManifestError(`${file2}: patchVersion requires manifest format 2`);
64141
+ }
64142
+ if (m2.version === 2) {
64143
+ for (const [i, p2] of m2.patches.entries()) {
64144
+ const min2 = parseSemver(p2.min);
64145
+ const max2 = parseSemver(p2.max);
64146
+ if (!Number.isSafeInteger(p2.patchVersion) || p2.patchVersion < 1 || min2.pre !== null || max2.pre !== null || compareSemver(min2, max2) > 0 || !/^[a-zA-Z0-9][a-zA-Z0-9._-]*\.patch$/.test(p2.file)) {
64147
+ throw new ManifestError(`${file2}: invalid patch version or range`);
64148
+ }
64149
+ if (m2.patches.slice(0, i).some((other) => compareSemver(min2, parseSemver(other.max)) <= 0 && compareSemver(max2, parseSemver(other.min)) >= 0)) {
64150
+ throw new ManifestError(`${file2}: overlapping Codex ranges have ambiguous patch ownership`);
64151
+ }
64152
+ }
64153
+ }
63967
64154
  return m2;
63968
64155
  } catch (e) {
63969
64156
  if (e instanceof ManifestError)
@@ -63979,7 +64166,7 @@ function resolvePatch(m2, v2) {
63979
64166
  const max2 = parseSemver(p2.max);
63980
64167
  return min2 && max2 && compareSemver(v2, min2) >= 0 && compareSemver(v2, max2) <= 0;
63981
64168
  });
63982
- return hit ? { file: hit.file, tag: `${m2.tag_prefix}${v2.raw}` } : null;
64169
+ return hit ? { file: hit.file, tag: `${m2.tag_prefix}${v2.raw}`, ...hit.patchVersion === undefined ? {} : { patchVersion: hit.patchVersion } } : null;
63983
64170
  }
63984
64171
  function supportedCodexVersions(m2) {
63985
64172
  const versions2 = new Set;
@@ -64005,7 +64192,7 @@ function isCodexVersionSupported(m2, version2) {
64005
64192
  // src/patch/wrapper.ts
64006
64193
  import { chmodSync as chmodSync4, closeSync as closeSync2, existsSync as existsSync11, lstatSync as lstatSync5, mkdirSync as mkdirSync7, openSync as openSync2, readFileSync as readFileSync12, readSync, renameSync as renameSync5, rmSync as rmSync4, statSync as statSync5, writeFileSync as writeFileSync3 } from "node:fs";
64007
64194
  import { randomBytes as randomBytes3 } from "node:crypto";
64008
- import { join as join18 } from "node:path";
64195
+ import { join as join17 } from "node:path";
64009
64196
  var WRAPPER_MARKER = "# cxstatusline-wrapper v1";
64010
64197
  var WRAPPER_MARKER_V2 = "# cxstatusline-wrapper v2";
64011
64198
  var WRAPPER_MARKERS = [WRAPPER_MARKER, WRAPPER_MARKER_V2];
@@ -64064,7 +64251,7 @@ function isSymlink(p2) {
64064
64251
  }
64065
64252
  }
64066
64253
  function stageExecutable(target, write) {
64067
- mkdirSync7(join18(target, ".."), { recursive: true });
64254
+ mkdirSync7(join17(target, ".."), { recursive: true });
64068
64255
  const tmp = `${target}.tmp-${process.pid}`;
64069
64256
  try {
64070
64257
  write(tmp);
@@ -64324,6 +64511,9 @@ async function prebuiltAcquisition(ctx, state, upstream, transport) {
64324
64511
  }
64325
64512
  let prepared;
64326
64513
  try {
64514
+ if (upstream.pre !== null) {
64515
+ throw new Error(`Cannot install a prebuilt for Codex ${upstream.raw}. Prebuilt binaries currently support stable releases only. Run cxstatusline install to choose a supported stable version.`);
64516
+ }
64327
64517
  prepared = await preparePrebuilt(ctx, expected, transport);
64328
64518
  } catch (e) {
64329
64519
  if (e instanceof ReleaseUnavailableError) {
@@ -64478,6 +64668,7 @@ function renderInstallFailure(outcome, advice) {
64478
64668
  return renderBox(lines, { borderColor: source_default.red, minWidth: 68 });
64479
64669
  }
64480
64670
  // src/ui/progress.ts
64671
+ var import_react39 = __toESM(require_react(), 1);
64481
64672
  function formatBytes2(bytes) {
64482
64673
  if (bytes <= 0)
64483
64674
  return "0 B";
@@ -64510,82 +64701,31 @@ function createInstallProgressTracker(io2, baseTransport = {}) {
64510
64701
  let downloadStart = 0;
64511
64702
  let initialLoaded = 0;
64512
64703
  let lastDownloadUpdate = 0;
64513
- let hasProgressBar = false;
64514
64704
  let lastReportedPct = -1;
64515
- let cursorHidden = false;
64516
- let stdinConfigured = false;
64517
- const hideCursor = () => {
64518
- if (isTTY && !cursorHidden) {
64519
- io2.write("\x1B[?25l");
64520
- cursorHidden = true;
64521
- }
64522
- };
64523
- const showCursor = () => {
64524
- if (isTTY && cursorHidden) {
64525
- io2.write("\x1B[?25h");
64526
- cursorHidden = false;
64527
- }
64528
- };
64529
- const handleStdinData = (data) => {
64530
- const str2 = typeof data === "string" ? data : data.toString("utf8");
64531
- if (str2 === "\x03") {
64532
- cleanupStdin();
64533
- showCursor();
64534
- if (typeof process !== "undefined" && typeof process.kill === "function") {
64535
- process.kill(process.pid, "SIGINT");
64536
- }
64537
- }
64538
- };
64539
- const setupStdin = () => {
64540
- if (!isTTY || stdinConfigured)
64541
- return;
64542
- if (typeof process !== "undefined" && process.stdin?.isTTY && typeof process.stdin.setRawMode === "function") {
64543
- try {
64544
- process.stdin.setRawMode(true);
64545
- process.stdin.resume();
64546
- process.stdin.on("data", handleStdinData);
64547
- stdinConfigured = true;
64548
- } catch {}
64549
- }
64550
- };
64551
- const cleanupStdin = () => {
64552
- if (!stdinConfigured)
64553
- return;
64554
- stdinConfigured = false;
64555
- if (typeof process !== "undefined" && process.stdin) {
64556
- try {
64557
- process.stdin.removeListener("data", handleStdinData);
64558
- if (typeof process.stdin.setRawMode === "function") {
64559
- process.stdin.setRawMode(false);
64560
- }
64561
- process.stdin.pause();
64562
- } catch {}
64563
- }
64564
- };
64565
- const onExit = () => {
64566
- cleanupStdin();
64567
- if (cursorHidden) {
64568
- try {
64569
- io2.write("\x1B[?25h");
64570
- } catch {}
64571
- cursorHidden = false;
64572
- }
64573
- };
64574
- const proc = typeof process !== "undefined" ? process : null;
64575
- if (proc?.once && isTTY) {
64576
- proc.once("exit", onExit);
64577
- proc.once("SIGINT", onExit);
64578
- proc.once("SIGTERM", onExit);
64579
- }
64705
+ let view;
64580
64706
  const clearProgressLine = () => {
64581
- if (hasProgressBar && isTTY) {
64582
- io2.write("\r\x1B[2K");
64583
- hasProgressBar = false;
64584
- }
64707
+ if (!view)
64708
+ return;
64709
+ view.rerender(import_react39.createElement(Text, {}, ""));
64710
+ view.clear();
64711
+ view.unmount();
64712
+ view.cleanup();
64713
+ view = undefined;
64714
+ };
64715
+ const showProgress = (text) => {
64716
+ const element = import_react39.createElement(Text, { wrap: "truncate-end" }, ` ${text}`);
64717
+ if (view)
64718
+ view.rerender(element);
64719
+ else
64720
+ view = render_default(element, {
64721
+ stdout: io2.stdout ?? process.stdout,
64722
+ exitOnCtrlC: false,
64723
+ patchConsole: false,
64724
+ preserveScrollback: true,
64725
+ isCI: false
64726
+ });
64585
64727
  };
64586
64728
  const onProgress = (loaded, total) => {
64587
- hideCursor();
64588
- setupStdin();
64589
64729
  const now2 = Date.now();
64590
64730
  if (!downloadStart) {
64591
64731
  downloadStart = now2;
@@ -64603,12 +64743,13 @@ function createInstallProgressTracker(io2, baseTransport = {}) {
64603
64743
  const ratio = Math.min(1, loaded / total);
64604
64744
  const pct = Math.floor(ratio * 100);
64605
64745
  if (isTTY) {
64606
- const bar = renderProgressBar(ratio, 24);
64607
64746
  const loadedStr = formatBytes2(loaded);
64608
64747
  const totalStr = formatBytes2(total);
64609
- const text = `\r\x1B[2K ${bar} ${source_default.bold(String(pct).padStart(3))}% ${loadedStr} / ${totalStr} (${source_default.dim(speedStr)})`;
64610
- io2.write(text);
64611
- hasProgressBar = true;
64748
+ const label = `${String(pct).padStart(3)}% ${loadedStr} / ${totalStr} (${speedStr})`;
64749
+ const columns = io2.stdout?.columns || process.stdout?.columns || 80;
64750
+ const barWidth = Math.max(4, Math.min(24, columns - 7 - label.length));
64751
+ const text = `${renderProgressBar(ratio, barWidth)} ${source_default.bold(`${String(pct).padStart(3)}%`)} ${loadedStr} / ${totalStr} (${source_default.dim(speedStr)})`;
64752
+ showProgress(text);
64612
64753
  } else {
64613
64754
  const milestone = Math.floor(pct / 25) * 25;
64614
64755
  if (milestone > lastReportedPct && milestone > 0) {
@@ -64618,8 +64759,7 @@ function createInstallProgressTracker(io2, baseTransport = {}) {
64618
64759
  }
64619
64760
  } else {
64620
64761
  if (isTTY) {
64621
- io2.write(`\r\x1B[2K ${symbols.activeBullet} ${formatBytes2(loaded)} downloaded (${source_default.dim(speedStr)})`);
64622
- hasProgressBar = true;
64762
+ showProgress(`${symbols.activeBullet} ${formatBytes2(loaded)} downloaded (${source_default.dim(speedStr)})`);
64623
64763
  }
64624
64764
  }
64625
64765
  };
@@ -64710,16 +64850,7 @@ function createInstallProgressTracker(io2, baseTransport = {}) {
64710
64850
  };
64711
64851
  return {
64712
64852
  transport,
64713
- finish: () => {
64714
- if (proc?.removeListener) {
64715
- proc.removeListener("exit", onExit);
64716
- proc.removeListener("SIGINT", onExit);
64717
- proc.removeListener("SIGTERM", onExit);
64718
- }
64719
- cleanupStdin();
64720
- clearProgressLine();
64721
- showCursor();
64722
- }
64853
+ finish: clearProgressLine
64723
64854
  };
64724
64855
  }
64725
64856
 
@@ -64778,17 +64909,11 @@ function fallbackAdvice(ctx, version2) {
64778
64909
  lines.push(`Tracking issue: ${url2}`);
64779
64910
  return lines;
64780
64911
  }
64781
- function report(ctx, outcome) {
64782
- ctx.say(describeOutcome(outcome));
64783
- if (outcome.kind === "unavailable")
64784
- for (const line of fallbackAdvice(ctx, outcome.version))
64785
- ctx.say(line);
64786
- }
64787
64912
  function runPatch(ctx, opts, transport = {}) {
64788
64913
  ctx.say(renderInstallHeader(true));
64789
64914
  const progress = createInstallProgressTracker({
64790
64915
  isTTY: process.stdout?.isTTY,
64791
- write: (s3) => process.stdout.write(s3),
64916
+ stdout: process.stdout,
64792
64917
  say: (l) => ctx.say(l)
64793
64918
  }, transport);
64794
64919
  return runAcquisition(ctx, { source: "compiled", force: opts.force }, progress.transport).finally(() => {
@@ -64799,7 +64924,7 @@ async function runInstall(ctx, opts, transport = {}) {
64799
64924
  ctx.say(renderInstallHeader(opts.compile));
64800
64925
  const progress = createInstallProgressTracker({
64801
64926
  isTTY: process.stdout?.isTTY,
64802
- write: (s3) => process.stdout.write(s3),
64927
+ stdout: process.stdout,
64803
64928
  say: (l) => ctx.say(l)
64804
64929
  }, transport);
64805
64930
  let outcome;
@@ -64855,18 +64980,6 @@ async function probeUpstreamLatest(fetchFn) {
64855
64980
  return null;
64856
64981
  }
64857
64982
  }
64858
- async function probePrebuiltExists(targetCodexVersion, cxVersionOrFetch, fetchFnOrBaseUrl, baseUrl) {
64859
- const fetchFn = typeof cxVersionOrFetch === "function" ? cxVersionOrFetch : fetchFnOrBaseUrl ?? globalThis.fetch;
64860
- const resolvedBaseUrl = typeof cxVersionOrFetch === "function" ? typeof fetchFnOrBaseUrl === "string" ? fetchFnOrBaseUrl : baseUrl : baseUrl;
64861
- try {
64862
- const tag = releaseTag(targetCodexVersion);
64863
- const url2 = resolvedBaseUrl ? `${resolvedBaseUrl}/${tag}/manifest.json` : `https://github.com/adrijshikhar/cxstatusline/releases/download/${tag}/manifest.json`;
64864
- const res = await fetchFn(url2, { method: "HEAD", signal: AbortSignal.timeout(5000) });
64865
- return res.ok || res.status === 302 || res.status === 301;
64866
- } catch {
64867
- return false;
64868
- }
64869
- }
64870
64983
  async function probeRemoteCandidate(targetCodexVersion, fetchFnOrBaseUrl, baseUrl) {
64871
64984
  const fetchFn = typeof fetchFnOrBaseUrl === "function" ? fetchFnOrBaseUrl : globalThis.fetch;
64872
64985
  const resolvedBaseUrl = typeof fetchFnOrBaseUrl === "string" ? fetchFnOrBaseUrl : baseUrl;
@@ -64883,155 +64996,190 @@ async function probeRemoteCandidate(targetCodexVersion, fetchFnOrBaseUrl, baseUr
64883
64996
  return null;
64884
64997
  }
64885
64998
  }
64886
- async function runUpdate(ctx, optsOrTransport = {}, maybeTransport) {
64887
- const isOpts = typeof optsOrTransport === "object" && optsOrTransport !== null && (("compile" in optsOrTransport) || ("force" in optsOrTransport) || ("isTTY" in optsOrTransport) || ("ask" in optsOrTransport) || ("fetchPrebuilts" in optsOrTransport));
64888
- let activeOpts = isOpts ? optsOrTransport : {};
64889
- const transport = !isOpts && (("baseUrl" in optsOrTransport) || ("fetch" in optsOrTransport)) ? optsOrTransport : maybeTransport ?? {};
64890
- const state = loadState(ctx);
64891
- const located = upstreamFor(ctx, state);
64892
- if ("reason" in located) {
64893
- ctx.say(`no upstream Codex to update: ${located.reason}`);
64999
+ async function runUpdate(ctx, opts = {}, transport = {}) {
65000
+ const manifest = loadManifest(ctx.patchesDir);
65001
+ const versions2 = opts.compile ? supportedCodexVersions(manifest) : await (opts.fetchPrebuilts ?? fetchPublishedPrebuiltVersions)(transport.fetch);
65002
+ const target = versions2.filter((version2) => isCodexVersionSupported(manifest, version2)).sort((a, b2) => compareSemver(parseSemver(b2), parseSemver(a)))[0];
65003
+ if (!target) {
65004
+ ctx.say(opts.compile ? "No supported source patch is available. Update the cxstatusline package and retry." : "No supported prebuilt release could be found. Check your connection or update the cxstatusline package and retry. Your installation is unchanged.");
64894
65005
  return 1;
64895
65006
  }
64896
- const current = readUpstreamVersion(located.bin, ctx.run);
64897
- const fetchFn = transport.fetch ?? fetch;
64898
- if (current && !activeOpts.force && !activeOpts.compile) {
64899
- const latest = await probeUpstreamLatest(fetchFn);
64900
- if (latest && latest !== current.raw) {
64901
- const available = await probePrebuiltExists(latest, fetchFn, transport.baseUrl);
64902
- if (!available) {
64903
- const prebuiltsFetcher = activeOpts.fetchPrebuilts ?? fetchPublishedPrebuiltVersions;
64904
- const publishedPrebuilts = await prebuiltsFetcher(fetchFn);
64905
- const currentSem = parseSemver(current.raw);
64906
- const newerPrebuilts = currentSem ? publishedPrebuilts.filter((v2) => {
64907
- const s3 = parseSemver(v2);
64908
- return s3 !== null && compareSemver(s3, currentSem) > 0;
64909
- }) : [];
64910
- const highestAvailable = newerPrebuilts[0];
64911
- if (highestAvailable) {
64912
- ctx.say(`Warning: Upstream Codex update available: ${current.raw} -> ${latest}.`);
64913
- ctx.say(`However, cxstatusline has not yet published prebuilt binaries for Codex ${latest}.`);
64914
- ctx.say(`Newer prebuilt available: Codex ${highestAvailable} is published and ready to install.`);
64915
- ctx.say("");
64916
- if (!activeOpts.isTTY) {
64917
- ctx.say("Options:");
64918
- ctx.say(` - Install latest available prebuilt: cxstatusline install --codex-version ${highestAvailable}`);
64919
- ctx.say(` - Wait until cxstatusline publishes prebuilt binaries for ${latest}.`);
64920
- ctx.say(" - Update and compile from source: cxstatusline update --compile");
64921
- ctx.say(" - Update to stock Codex anyway: cxstatusline update --force");
64922
- return 1;
64923
- }
64924
- ctx.say("How would you like to proceed?");
64925
- ctx.say(` 1) Install latest available prebuilt (Codex ${highestAvailable}) [recommended]`);
64926
- ctx.say(` 2) Compile Codex ${latest} from source`);
64927
- ctx.say(` 3) Update to stock Codex ${latest} anyway`);
64928
- ctx.say(" 4) Cancel");
64929
- const askFn = activeOpts.ask ?? defaultAsk;
64930
- let selectedAction = null;
64931
- while (!selectedAction) {
64932
- const choice = (await askFn("Enter choice [1-4] (default 1): ")).trim();
64933
- if (choice === "1" || choice === "") {
64934
- selectedAction = "prebuilt";
64935
- } else if (choice === "2") {
64936
- selectedAction = "compile";
64937
- } else if (choice === "3") {
64938
- selectedAction = "stock";
64939
- } else if (choice === "4") {
64940
- selectedAction = "cancel";
64941
- } else {
64942
- ctx.say(`Invalid choice "${choice}". Please select 1, 2, 3, or 4.`);
64943
- }
64944
- }
64945
- if (selectedAction === "prebuilt") {
64946
- ctx.say(`Installing prebuilt binaries for Codex ${highestAvailable}...`);
64947
- return runInstall(ctx, { compile: false, codexVersion: highestAvailable }, transport);
64948
- }
64949
- if (selectedAction === "cancel") {
64950
- ctx.say("Update cancelled.");
64951
- return 0;
64952
- }
64953
- if (selectedAction === "compile") {
64954
- activeOpts = { ...activeOpts, compile: true };
64955
- } else if (selectedAction === "stock") {
64956
- activeOpts = { ...activeOpts, force: true };
64957
- }
64958
- } else {
64959
- ctx.say(`Warning: Upstream Codex update available: ${current.raw} -> ${latest}.`);
64960
- ctx.say(`However, cxstatusline has not yet published prebuilt binaries for Codex ${latest}.`);
64961
- ctx.say("Updating now will replace your patched launcher with stock Codex.");
64962
- ctx.say("");
64963
- if (!activeOpts.isTTY) {
64964
- ctx.say("Options:");
64965
- ctx.say(" - Wait until cxstatusline publishes prebuilt binaries for this version.");
64966
- ctx.say(" - Update and compile from source: cxstatusline update --compile");
64967
- ctx.say(" - Update to stock Codex anyway: cxstatusline update --force");
64968
- return 1;
64969
- }
64970
- ctx.say("How would you like to proceed?");
64971
- ctx.say(` 1) Compile Codex ${latest} from source`);
64972
- ctx.say(` 2) Update to stock Codex ${latest} anyway`);
64973
- ctx.say(" 3) Cancel");
64974
- const askFn = activeOpts.ask ?? defaultAsk;
64975
- let selectedAction = null;
64976
- while (!selectedAction) {
64977
- const choice = (await askFn("Enter choice [1-3] (default 3): ")).trim();
64978
- if (choice === "1") {
64979
- selectedAction = "compile";
64980
- } else if (choice === "2") {
64981
- selectedAction = "stock";
64982
- } else if (choice === "3" || choice === "") {
64983
- selectedAction = "cancel";
64984
- } else {
64985
- ctx.say(`Invalid choice "${choice}". Please select 1, 2, or 3.`);
64986
- }
64987
- }
64988
- if (selectedAction === "cancel") {
64989
- ctx.say("Update cancelled.");
64990
- return 0;
64991
- }
64992
- if (selectedAction === "compile") {
64993
- activeOpts = { ...activeOpts, compile: true };
64994
- } else if (selectedAction === "stock") {
64995
- activeOpts = { ...activeOpts, force: true };
64996
- }
64997
- }
64998
- }
64999
- } else if (latest && latest === current.raw) {
65000
- ctx.say(`Codex is already at the latest version (${current.raw}).`);
65007
+ const installed = readInstallation(ctx.paths)?.codexVersion ?? loadState(ctx).patched_from;
65008
+ const current = installed ? parseSemver(installed) : null;
65009
+ if (current && compareSemver(current, parseSemver(target)) > 0) {
65010
+ ctx.say(`Installed Codex ${installed} is newer than the latest supported ${opts.compile ? "patch" : "prebuilt"} (${target}); leaving it unchanged.`);
65011
+ return 0;
65012
+ }
65013
+ if (opts.isTTY && !opts.force && !opts.compile) {
65014
+ const action = await (opts.promptUpdate ?? promptUpdate)({ latest: target, highestAvailable: target });
65015
+ if (action === "cancel") {
65016
+ ctx.say("Update cancelled.");
65001
65017
  return 0;
65002
65018
  }
65019
+ if (action === "compile")
65020
+ return runInstall(ctx, { compile: true, codexVersion: target }, transport);
65003
65021
  }
65004
- ctx.say(`running upstream updater: ${located.bin} update`);
65005
- const r = ctx.run(located.bin, ["update"], { interactive: true });
65006
- if (r.status !== 0) {
65007
- ctx.say(`upstream updater exited ${String(r.status)}; see its output above. Not installing.`);
65008
- return 1;
65009
- }
65010
- const source = activeOpts.compile ? "compiled" : "prebuilt";
65011
- const progress = createInstallProgressTracker({
65012
- isTTY: process.stdout?.isTTY,
65013
- write: (s3) => process.stdout.write(s3),
65014
- say: (l) => ctx.say(l)
65015
- }, transport);
65016
- let outcome;
65017
- try {
65018
- outcome = await runAcquisition(ctx, { source, force: true }, progress.transport);
65019
- } finally {
65020
- progress.finish();
65021
- }
65022
- report(ctx, outcome);
65023
- return outcome.kind === "installed" ? 0 : 1;
65022
+ return runInstall(ctx, { compile: opts.compile ?? false, codexVersion: target }, transport);
65024
65023
  }
65025
65024
  function appendLog(file2, line) {
65026
- mkdirSync8(join19(file2, ".."), { recursive: true });
65025
+ mkdirSync8(join18(file2, ".."), { recursive: true });
65027
65026
  appendFileSync(file2, `${new Date().toISOString()} ${line}
65028
65027
  `);
65029
65028
  }
65030
65029
 
65030
+ // src/ui/prompt-version.ts
65031
+ var import_react41 = __toESM(require_react(), 1);
65032
+
65033
+ // src/ui/VersionPicker.tsx
65034
+ var import_react40 = __toESM(require_react(), 1);
65035
+ var jsx_dev_runtime12 = __toESM(require_jsx_dev_runtime(), 1);
65036
+ function VersionPicker({ supportedVersions, prebuiltVersions, defaultVersion, compile: compile3 = false, onSelect }) {
65037
+ const { usable, maxVisibleItems } = useTerminalSize();
65038
+ const [selectedIndex, setSelectedIndex] = import_react40.useState(Math.max(0, supportedVersions.indexOf(defaultVersion ?? "")));
65039
+ const [sourceVersion, setSourceVersion] = import_react40.useState(null);
65040
+ use_input_default((input2, key) => {
65041
+ if (!usable) {
65042
+ if (key.escape || key.ctrl && input2 === "c")
65043
+ onSelect(null);
65044
+ return;
65045
+ }
65046
+ if (key.ctrl && input2 === "c")
65047
+ onSelect(null);
65048
+ else if (key.escape) {
65049
+ if (sourceVersion)
65050
+ setSourceVersion(null);
65051
+ else
65052
+ onSelect(null);
65053
+ }
65054
+ });
65055
+ if (!usable)
65056
+ return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
65057
+ flexDirection: "column",
65058
+ marginY: 1,
65059
+ children: [
65060
+ /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
65061
+ children: "Resize terminal to at least 40 columns × 20 rows to continue."
65062
+ }, undefined, false, undefined, this),
65063
+ /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
65064
+ dimColor: true,
65065
+ children: "Esc/Ctrl+C cancel"
65066
+ }, undefined, false, undefined, this)
65067
+ ]
65068
+ }, undefined, true, undefined, this);
65069
+ if (sourceVersion) {
65070
+ return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
65071
+ flexDirection: "column",
65072
+ marginY: 1,
65073
+ children: [
65074
+ /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
65075
+ bold: true,
65076
+ children: [
65077
+ "Build Codex ",
65078
+ sourceVersion,
65079
+ " from source?"
65080
+ ]
65081
+ }, undefined, true, undefined, this),
65082
+ /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
65083
+ children: "No prebuilt is published for this version."
65084
+ }, undefined, false, undefined, this),
65085
+ /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
65086
+ dimColor: true,
65087
+ children: "Requires Rust, at least 20 GiB free, and may take tens of minutes."
65088
+ }, undefined, false, undefined, this),
65089
+ /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(List, {
65090
+ marginTop: 1,
65091
+ maxVisibleItems,
65092
+ items: [
65093
+ { label: "Back to versions", value: "back" },
65094
+ { label: "Compile from source", value: "compile" }
65095
+ ],
65096
+ onSelect: (value) => value === "compile" ? onSelect({ version: sourceVersion, compile: true }) : setSourceVersion(null)
65097
+ }, "confirm", false, undefined, this),
65098
+ /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
65099
+ marginTop: 1,
65100
+ children: /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
65101
+ dimColor: true,
65102
+ children: "↑/↓ navigate · Enter select · Esc back · Ctrl+C cancel"
65103
+ }, undefined, false, undefined, this)
65104
+ }, undefined, false, undefined, this)
65105
+ ]
65106
+ }, undefined, true, undefined, this);
65107
+ }
65108
+ return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
65109
+ flexDirection: "column",
65110
+ marginY: 1,
65111
+ children: [
65112
+ /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
65113
+ bold: true,
65114
+ children: "Select Codex version to install"
65115
+ }, undefined, false, undefined, this),
65116
+ /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(List, {
65117
+ marginTop: 1,
65118
+ maxVisibleItems,
65119
+ initialSelection: selectedIndex,
65120
+ onSelectionChange: (_2, index) => setSelectedIndex(index),
65121
+ items: supportedVersions.map((version2) => {
65122
+ const source = compile3 || Boolean(prebuiltVersions && !prebuiltVersions.includes(version2));
65123
+ return {
65124
+ value: version2,
65125
+ label: version2,
65126
+ sublabel: `${source ? "build from source" : "prebuilt"}${version2 === defaultVersion ? " · default" : ""}`,
65127
+ description: source ? "Builds locally with Rust. Requires at least 20 GiB free." : "Downloads a verified prebuilt. No Rust toolchain needed."
65128
+ };
65129
+ }),
65130
+ onSelect: (version2, index) => {
65131
+ if (version2 === "back")
65132
+ return;
65133
+ setSelectedIndex(index);
65134
+ if (!compile3 && prebuiltVersions && !prebuiltVersions.includes(version2))
65135
+ setSourceVersion(version2);
65136
+ else
65137
+ onSelect({ version: version2, compile: compile3 });
65138
+ }
65139
+ }, "versions", false, undefined, this),
65140
+ /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
65141
+ marginTop: 1,
65142
+ children: /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
65143
+ dimColor: true,
65144
+ children: "↑/↓ navigate · Enter select · Esc/Ctrl+C cancel"
65145
+ }, undefined, false, undefined, this)
65146
+ }, undefined, false, undefined, this)
65147
+ ]
65148
+ }, undefined, true, undefined, this);
65149
+ }
65150
+
65151
+ // src/ui/prompt-version.ts
65152
+ async function promptCodexVersion(options) {
65153
+ const { supportedVersions, prebuiltVersions, isTTY = false, say = (s3) => console.log(s3) } = options;
65154
+ if (supportedVersions.length === 0) {
65155
+ throw new Error("No supported Codex versions available.");
65156
+ }
65157
+ let defaultVersion;
65158
+ if (options.defaultVersion && supportedVersions.includes(options.defaultVersion)) {
65159
+ defaultVersion = options.defaultVersion;
65160
+ } else if (prebuiltVersions && prebuiltVersions.length > 0) {
65161
+ defaultVersion = supportedVersions.find((v2) => prebuiltVersions.includes(v2)) ?? supportedVersions[0];
65162
+ } else {
65163
+ defaultVersion = supportedVersions[0];
65164
+ }
65165
+ if (!isTTY) {
65166
+ const isSourceOnly = Boolean(prebuiltVersions && !prebuiltVersions.includes(defaultVersion));
65167
+ return { version: defaultVersion, compile: options.compile || isSourceOnly };
65168
+ }
65169
+ const selection = await prompt((onSelect) => import_react41.createElement(VersionPicker, {
65170
+ ...options,
65171
+ defaultVersion,
65172
+ onSelect
65173
+ }), null);
65174
+ if (selection)
65175
+ say(`Selected Codex ${selection.version} (${selection.compile ? "build from source" : "prebuilt"}).`);
65176
+ return selection;
65177
+ }
65178
+
65031
65179
  // src/hook/run.ts
65032
65180
  import { appendFileSync as appendFileSync2, closeSync as closeSync3, existsSync as existsSync12, mkdirSync as mkdirSync9, openSync as openSync3 } from "node:fs";
65033
65181
  import { spawn as spawn2 } from "node:child_process";
65034
- import { dirname as dirname10 } from "node:path";
65182
+ import { dirname as dirname9 } from "node:path";
65035
65183
  var HOOK_SOURCES = ["startup", "resume", "clear"];
65036
65184
  function parseHookInput(stdin) {
65037
65185
  try {
@@ -65158,7 +65306,7 @@ function realHookDeps() {
65158
65306
  spawnDetached(cxBin, args, logFile) {
65159
65307
  let fd;
65160
65308
  try {
65161
- mkdirSync9(dirname10(logFile), { recursive: true });
65309
+ mkdirSync9(dirname9(logFile), { recursive: true });
65162
65310
  fd = openSync3(logFile, "a");
65163
65311
  const child = spawn2(cxBin, args, { detached: true, stdio: ["ignore", fd, fd], env: process.env });
65164
65312
  child.on("error", (err) => {
@@ -65182,7 +65330,7 @@ function realHookDeps() {
65182
65330
 
65183
65331
  // src/commands/doctor.ts
65184
65332
  import { existsSync as existsSync14, lstatSync as lstatSync6, readFileSync as readFileSync14, readlinkSync as readlinkSync3, readdirSync as readdirSync3 } from "node:fs";
65185
- import { join as join21 } from "node:path";
65333
+ import { join as join20 } from "node:path";
65186
65334
 
65187
65335
  // src/utils/format.ts
65188
65336
  function formatDuration2(ms2) {
@@ -65200,11 +65348,11 @@ function formatDuration2(ms2) {
65200
65348
  // src/commands/doctor-generation.ts
65201
65349
  import { createHash as createHash6 } from "node:crypto";
65202
65350
  import { existsSync as existsSync13, readFileSync as readFileSync13 } from "node:fs";
65203
- import { dirname as dirname11, isAbsolute as isAbsolute3, join as join20, resolve as resolve4 } from "node:path";
65351
+ import { dirname as dirname10, isAbsolute as isAbsolute3, join as join19, resolve as resolve4 } from "node:path";
65204
65352
  var line = (key, value, ok = null) => ({ key, value, ok });
65205
65353
  var NO_GENERATION = "n/a (no active generation)";
65206
65354
  function resolvePointerTarget(paths, raw) {
65207
- return isAbsolute3(raw) ? raw : resolve4(dirname11(paths.currentGeneration), raw);
65355
+ return isAbsolute3(raw) ? raw : resolve4(dirname10(paths.currentGeneration), raw);
65208
65356
  }
65209
65357
  function computeGenerationLine(paths, pointer) {
65210
65358
  const dir = activeGeneration(paths);
@@ -65279,7 +65427,7 @@ function upstreamCommitLine(record2) {
65279
65427
  function digestLine(key, label, record2, dir) {
65280
65428
  if (!record2 || !dir)
65281
65429
  return line(label, NO_GENERATION, null);
65282
- const file2 = join20(dir, key);
65430
+ const file2 = join19(dir, key);
65283
65431
  if (!existsSync13(file2))
65284
65432
  return line(label, "missing", false);
65285
65433
  let buf;
@@ -65297,7 +65445,7 @@ function digestLine(key, label, record2, dir) {
65297
65445
  function codexVersionLine(ctx, record2, dir) {
65298
65446
  if (!record2 || !dir)
65299
65447
  return line("codex_version", NO_GENERATION, null);
65300
- const bin = join20(dir, "codex");
65448
+ const bin = join19(dir, "codex");
65301
65449
  if (!existsSync13(bin))
65302
65450
  return line("codex_version", "missing", false);
65303
65451
  let result2;
@@ -65320,7 +65468,7 @@ function legalLine(record2, dir) {
65320
65468
  return line("legal", "n/a (compiled build)", null);
65321
65469
  if (!dir)
65322
65470
  return line("legal", NO_GENERATION, null);
65323
- const missing = GENERATION_LEGAL_FILES.filter((f2) => !existsSync13(join20(dir, f2)));
65471
+ const missing = GENERATION_LEGAL_FILES.filter((f2) => !existsSync13(join19(dir, f2)));
65324
65472
  return missing.length === 0 ? line("legal", "present", true) : line("legal", `missing: ${missing.join(", ")}`, false);
65325
65473
  }
65326
65474
  function generationDetailLines(ctx, status) {
@@ -65544,7 +65692,7 @@ function commandCacheLine(ctx) {
65544
65692
  let oldestMtime = Infinity;
65545
65693
  for (const f2 of entries) {
65546
65694
  try {
65547
- const st2 = lstatSync6(join21(dir, f2));
65695
+ const st2 = lstatSync6(join20(dir, f2));
65548
65696
  if (st2.mtimeMs < oldestMtime)
65549
65697
  oldestMtime = st2.mtimeMs;
65550
65698
  } catch {}
@@ -65646,6 +65794,7 @@ async function doctorReport(ctx, opts) {
65646
65794
  line2("settings", `${ctx.paths.settingsFile} ${existsSync14(ctx.paths.settingsFile) ? "present" : "absent (written on first render)"}`),
65647
65795
  upstreamLine(ctx, upstreamBin, upstream?.raw ?? null, lookupNote),
65648
65796
  line2("state", corrupt ? `${ctx.paths.stateFile} CORRUPT (recovered from ${ctx.paths.stateBackupFile} where possible)` : ctx.paths.stateFile, corrupt ? false : null),
65797
+ line2("patch_version", status.record?.provenance.patchVersion === undefined ? "unknown (legacy)" : `v${status.record.provenance.patchVersion}`),
65649
65798
  line2("patched_from", state.patched_from ?? "never"),
65650
65799
  line2("policy", state.policy),
65651
65800
  codexTarget,
@@ -65715,7 +65864,7 @@ function runPolicy(ctx, argv, io2) {
65715
65864
 
65716
65865
  // src/commands/revert.ts
65717
65866
  import { existsSync as existsSync15, lstatSync as lstatSync7, readdirSync as readdirSync4, rmSync as rmSync6, symlinkSync as symlinkSync2 } from "node:fs";
65718
- import { join as join22 } from "node:path";
65867
+ import { join as join21 } from "node:path";
65719
65868
  function safeIsSymlink(p2) {
65720
65869
  try {
65721
65870
  return lstatSync7(p2).isSymbolicLink();
@@ -65762,7 +65911,7 @@ function removeStagingDebris(ctx, actions) {
65762
65911
  return;
65763
65912
  const debris = readdirSync4(libexecDir).filter((n) => OWNED_LIBEXEC_PREFIXES.some((p2) => n.startsWith(p2)));
65764
65913
  for (const name of debris)
65765
- rmSync6(join22(libexecDir, name), { recursive: true, force: true });
65914
+ rmSync6(join21(libexecDir, name), { recursive: true, force: true });
65766
65915
  if (debris.length > 0) {
65767
65916
  actions.push(`removed ${debris.length} leftover staging entr${debris.length === 1 ? "y" : "ies"} from ${libexecDir}`);
65768
65917
  }
@@ -65812,7 +65961,7 @@ function revertLocked(ctx) {
65812
65961
 
65813
65962
  // src/tui/App.tsx
65814
65963
  import { readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
65815
- var import_react46 = __toESM(require_react(), 1);
65964
+ var import_react52 = __toESM(require_react(), 1);
65816
65965
 
65817
65966
  // src/utils/presets.ts
65818
65967
  function isRecord2(value) {
@@ -65858,121 +66007,27 @@ function previewImport(raw) {
65858
66007
  const omittedTypes = [];
65859
66008
  const lines = raw.lines.map((line3) => {
65860
66009
  if (!Array.isArray(line3))
65861
- throw new Error("Each preset line must be an array.");
65862
- const normalized = normalizeImportedItems(line3);
65863
- for (const type of normalized.omittedTypes)
65864
- addOnce(omittedTypes, type);
65865
- return normalized.items;
65866
- });
65867
- const parsed = SettingsSchema.safeParse({ ...raw, version: CURRENT_VERSION, lines });
65868
- if (!parsed.success)
65869
- throw new Error(`Invalid preset: ${parsed.error.issues[0]?.message ?? "settings validation failed"}`);
65870
- return { settings: parsed.data, omittedTypes };
65871
- }
65872
- function exportPreset(settings) {
65873
- return `${JSON.stringify(SettingsSchema.parse(settings), null, 2)}
65874
- `;
65875
- }
65876
-
65877
- // src/tui/components/ColorMenu.tsx
65878
- var import_react38 = __toESM(require_react(), 1);
65879
-
65880
- // src/tui/components/List.tsx
65881
- var import_react35 = __toESM(require_react(), 1);
65882
- var jsx_dev_runtime10 = __toESM(require_jsx_dev_runtime(), 1);
65883
- function List({
65884
- items,
65885
- onSelect,
65886
- onSelectionChange,
65887
- initialSelection = 0,
65888
- showBackButton = false,
65889
- color,
65890
- wrapNavigation = true,
65891
- ...boxProps
65892
- }) {
65893
- const [selectedIndex, setSelectedIndex] = import_react35.useState(initialSelection);
65894
- const latestOnSelectionChange = import_react35.useRef(onSelectionChange);
65895
- const displayedItems = import_react35.useMemo(() => showBackButton ? [...items, "-", { label: "← Back", value: "back" }] : [...items], [items, showBackButton]);
65896
- const selectableItems = displayedItems.filter((item) => item !== "-" && !item.disabled);
65897
- const selectedItem = selectableItems[selectedIndex];
65898
- const actualIndex = displayedItems.findIndex((item) => item === selectedItem);
65899
- import_react35.useEffect(() => {
65900
- latestOnSelectionChange.current = onSelectionChange;
65901
- }, [onSelectionChange]);
65902
- import_react35.useEffect(() => {
65903
- setSelectedIndex(Math.min(initialSelection, Math.max(0, selectableItems.length - 1)));
65904
- }, [initialSelection, selectableItems.length]);
65905
- import_react35.useEffect(() => {
65906
- if (selectedItem)
65907
- latestOnSelectionChange.current?.(selectedItem.value, selectedIndex);
65908
- }, [selectedIndex, selectedItem]);
65909
- use_input_default((_2, key) => {
65910
- if (!selectableItems.length)
65911
- return;
65912
- if (key.upArrow) {
65913
- setSelectedIndex((current) => current === 0 ? wrapNavigation ? selectableItems.length - 1 : 0 : current - 1);
65914
- return;
65915
- }
65916
- if (key.downArrow) {
65917
- setSelectedIndex((current) => current === selectableItems.length - 1 ? wrapNavigation ? 0 : selectableItems.length - 1 : current + 1);
65918
- return;
65919
- }
65920
- if (key.return && selectedItem)
65921
- onSelect(selectedItem.value, selectedIndex);
66010
+ throw new Error("Each preset line must be an array.");
66011
+ const normalized = normalizeImportedItems(line3);
66012
+ for (const type of normalized.omittedTypes)
66013
+ addOnce(omittedTypes, type);
66014
+ return normalized.items;
65922
66015
  });
65923
- return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
65924
- flexDirection: "column",
65925
- ...boxProps,
65926
- children: [
65927
- displayedItems.map((item, index) => {
65928
- if (item === "-")
65929
- return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
65930
- children: " "
65931
- }, index, false, undefined, this);
65932
- return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(ListItem, {
65933
- isSelected: index === actualIndex,
65934
- ...color && { color },
65935
- ...item.disabled !== undefined && { disabled: item.disabled },
65936
- ...item.props,
65937
- children: [
65938
- /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
65939
- children: item.label
65940
- }, undefined, false, undefined, this),
65941
- item.sublabel && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
65942
- dimColor: index !== actualIndex,
65943
- children: ` ${item.sublabel}`
65944
- }, undefined, false, undefined, this)
65945
- ]
65946
- }, item.value, true, undefined, this);
65947
- }),
65948
- selectedItem?.description && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
65949
- marginTop: 1,
65950
- paddingLeft: 2,
65951
- children: /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
65952
- dimColor: true,
65953
- wrap: "wrap",
65954
- children: selectedItem.description
65955
- }, undefined, false, undefined, this)
65956
- }, undefined, false, undefined, this)
65957
- ]
65958
- }, undefined, true, undefined, this);
66016
+ const parsed = SettingsSchema.safeParse({ ...raw, version: CURRENT_VERSION, lines });
66017
+ if (!parsed.success)
66018
+ throw new Error(`Invalid preset: ${parsed.error.issues[0]?.message ?? "settings validation failed"}`);
66019
+ return { settings: parsed.data, omittedTypes };
65959
66020
  }
65960
- function ListItem({ children, isSelected, color = "green", disabled, ...boxProps }) {
65961
- return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
65962
- ...boxProps,
65963
- children: /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
65964
- ...isSelected && { color },
65965
- ...disabled && { dimColor: true },
65966
- children: [
65967
- isSelected ? "▶ " : " ",
65968
- children
65969
- ]
65970
- }, undefined, true, undefined, this)
65971
- }, undefined, false, undefined, this);
66021
+ function exportPreset(settings) {
66022
+ return `${JSON.stringify(SettingsSchema.parse(settings), null, 2)}
66023
+ `;
65972
66024
  }
65973
66025
 
66026
+ // src/tui/components/ColorMenu.tsx
66027
+ var import_react44 = __toESM(require_react(), 1);
66028
+
65974
66029
  // src/tui/components/ConfirmDialog.tsx
65975
- var jsx_dev_runtime11 = __toESM(require_jsx_dev_runtime(), 1);
66030
+ var jsx_dev_runtime13 = __toESM(require_jsx_dev_runtime(), 1);
65976
66031
  var OPTIONS = [
65977
66032
  { label: "Yes", value: true },
65978
66033
  { label: "No", value: false }
@@ -65982,18 +66037,18 @@ function ConfirmDialog({ message, onConfirm, onCancel, inline = false }) {
65982
66037
  if (key.escape)
65983
66038
  onCancel();
65984
66039
  });
65985
- const list = /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(List, {
66040
+ const list = /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(List, {
65986
66041
  items: OPTIONS,
65987
66042
  color: "cyan",
65988
66043
  onSelect: (confirmed) => confirmed ? onConfirm() : onCancel()
65989
66044
  }, undefined, false, undefined, this);
65990
- return inline ? list : /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
66045
+ return inline ? list : /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
65991
66046
  flexDirection: "column",
65992
66047
  children: [
65993
- message && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
66048
+ message && /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
65994
66049
  children: message
65995
66050
  }, undefined, false, undefined, this),
65996
- /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
66051
+ /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
65997
66052
  marginTop: 1,
65998
66053
  children: list
65999
66054
  }, undefined, false, undefined, this)
@@ -66002,14 +66057,14 @@ function ConfirmDialog({ message, onConfirm, onCancel, inline = false }) {
66002
66057
  }
66003
66058
 
66004
66059
  // src/tui/components/ItemsEditor.tsx
66005
- var import_react37 = __toESM(require_react(), 1);
66060
+ var import_react43 = __toESM(require_react(), 1);
66006
66061
 
66007
66062
  // src/tui/components/HideStatesEditor.tsx
66008
- var import_react36 = __toESM(require_react(), 1);
66009
- var jsx_dev_runtime12 = __toESM(require_jsx_dev_runtime(), 1);
66063
+ var import_react42 = __toESM(require_react(), 1);
66064
+ var jsx_dev_runtime14 = __toESM(require_jsx_dev_runtime(), 1);
66010
66065
  var HideStatesEditor = ({ widget, states, onComplete, onCancel }) => {
66011
- const [selectedIndex, setSelectedIndex] = import_react36.useState(0);
66012
- const [enabledKeys, setEnabledKeys] = import_react36.useState(() => getEnabledHideStates(widget, states));
66066
+ const [selectedIndex, setSelectedIndex] = import_react42.useState(0);
66067
+ const [enabledKeys, setEnabledKeys] = import_react42.useState(() => getEnabledHideStates(widget, states));
66013
66068
  use_input_default((input2, key) => {
66014
66069
  if (key.return) {
66015
66070
  onComplete(setEnabledHideStates(widget, states, enabledKeys));
@@ -66026,35 +66081,35 @@ var HideStatesEditor = ({ widget, states, onComplete, onCancel }) => {
66026
66081
  }
66027
66082
  }
66028
66083
  });
66029
- return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
66084
+ return /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
66030
66085
  flexDirection: "column",
66031
66086
  children: [
66032
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
66087
+ /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66033
66088
  bold: true,
66034
66089
  children: "Hide"
66035
66090
  }, undefined, false, undefined, this),
66036
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
66091
+ /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66037
66092
  dimColor: true,
66038
66093
  children: "↑↓ select, Space toggle, Enter save, ESC cancel"
66039
66094
  }, undefined, false, undefined, this),
66040
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
66095
+ /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
66041
66096
  marginTop: 1,
66042
66097
  flexDirection: "column",
66043
66098
  children: states.map((state, index) => {
66044
66099
  const isSelected = index === selectedIndex;
66045
66100
  const isEnabled = enabledKeys.includes(state.key);
66046
- return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
66101
+ return /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
66047
66102
  flexDirection: "row",
66048
66103
  flexWrap: "nowrap",
66049
66104
  children: [
66050
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
66105
+ /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
66051
66106
  width: 3,
66052
- children: /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
66107
+ children: /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66053
66108
  color: isSelected ? "green" : undefined,
66054
66109
  children: isSelected ? "▶ " : " "
66055
66110
  }, undefined, false, undefined, this)
66056
66111
  }, undefined, false, undefined, this),
66057
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
66112
+ /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66058
66113
  color: isSelected ? "green" : undefined,
66059
66114
  children: `[${isEnabled ? "x" : " "}] ${state.label}`
66060
66115
  }, undefined, false, undefined, this)
@@ -66303,7 +66358,7 @@ function handleNormalInputMode({
66303
66358
  }
66304
66359
 
66305
66360
  // src/tui/components/ItemsEditor.tsx
66306
- var jsx_dev_runtime13 = __toESM(require_jsx_dev_runtime(), 1);
66361
+ var jsx_dev_runtime15 = __toESM(require_jsx_dev_runtime(), 1);
66307
66362
  function displayWidgetType(type) {
66308
66363
  if (type === "flex-separator")
66309
66364
  return "Flex Separator";
@@ -66354,13 +66409,13 @@ function newWidget(type) {
66354
66409
  };
66355
66410
  }
66356
66411
  function ItemsEditor({ widgets, onUpdate, onBack, lineNumber, settings: _settings }) {
66357
- const [selectedIndex, setSelectedIndex] = import_react37.useState(0);
66358
- const [moveMode, setMoveMode] = import_react37.useState(false);
66359
- const [showClearConfirm, setShowClearConfirm] = import_react37.useState(false);
66360
- const [widgetPicker, setWidgetPicker] = import_react37.useState(null);
66361
- const [customEditor, setCustomEditor] = import_react37.useState(null);
66362
- const widgetCatalog = import_react37.useMemo(buildCatalog, []);
66363
- const widgetCategories = import_react37.useMemo(() => ["All", ...new Set(widgetCatalog.map((entry) => entry.category))], [widgetCatalog]);
66412
+ const [selectedIndex, setSelectedIndex] = import_react43.useState(0);
66413
+ const [moveMode, setMoveMode] = import_react43.useState(false);
66414
+ const [showClearConfirm, setShowClearConfirm] = import_react43.useState(false);
66415
+ const [widgetPicker, setWidgetPicker] = import_react43.useState(null);
66416
+ const [customEditor, setCustomEditor] = import_react43.useState(null);
66417
+ const widgetCatalog = import_react43.useMemo(buildCatalog, []);
66418
+ const widgetCategories = import_react43.useMemo(() => ["All", ...new Set(widgetCatalog.map((entry) => entry.category))], [widgetCatalog]);
66364
66419
  const openWidgetPicker = (action) => {
66365
66420
  const selectedType = action === "change" ? widgets[selectedIndex]?.type ?? null : null;
66366
66421
  setWidgetPicker(normalizePickerState({
@@ -66417,7 +66472,7 @@ function ItemsEditor({ widgets, onUpdate, onBack, lineNumber, settings: _setting
66417
66472
  });
66418
66473
  });
66419
66474
  if (customEditor?.action === EDIT_HIDE_STATES_ACTION) {
66420
- return /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(HideStatesEditor, {
66475
+ return /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(HideStatesEditor, {
66421
66476
  widget: customEditor.widget,
66422
66477
  states: customEditor.impl.getHideableStates?.() ?? [],
66423
66478
  onComplete: (updated) => {
@@ -66437,15 +66492,15 @@ function ItemsEditor({ widgets, onUpdate, onBack, lineNumber, settings: _setting
66437
66492
  },
66438
66493
  onCancel: () => setCustomEditor(null)
66439
66494
  });
66440
- return editor ?? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66495
+ return editor ?? /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66441
66496
  children: "Unknown editor"
66442
66497
  }, undefined, false, undefined, this);
66443
66498
  }
66444
66499
  if (showClearConfirm) {
66445
- return /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
66500
+ return /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
66446
66501
  flexDirection: "column",
66447
66502
  children: [
66448
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66503
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66449
66504
  bold: true,
66450
66505
  children: [
66451
66506
  "Clear every widget from Line ",
@@ -66453,7 +66508,7 @@ function ItemsEditor({ widgets, onUpdate, onBack, lineNumber, settings: _setting
66453
66508
  "?"
66454
66509
  ]
66455
66510
  }, undefined, true, undefined, this),
66456
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(ConfirmDialog, {
66511
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(ConfirmDialog, {
66457
66512
  inline: true,
66458
66513
  onConfirm: () => {
66459
66514
  onUpdate([]);
@@ -66469,36 +66524,36 @@ function ItemsEditor({ widgets, onUpdate, onBack, lineNumber, settings: _setting
66469
66524
  const topLevelSearch = widgetPicker.level === "category" && widgetPicker.categoryQuery.trim().length > 0;
66470
66525
  const query = topLevelSearch ? widgetPicker.categoryQuery : widgetPicker.widgetQuery;
66471
66526
  const entries = filterWidgetCatalog(widgetCatalog, topLevelSearch ? "All" : widgetPicker.selectedCategory ?? "All", query);
66472
- return /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
66527
+ return /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
66473
66528
  flexDirection: "column",
66474
66529
  children: [
66475
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66530
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66476
66531
  bold: true,
66477
66532
  children: widgetPicker.action === "change" ? "Change Widget" : "Add Widget"
66478
66533
  }, undefined, false, undefined, this),
66479
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66534
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66480
66535
  dimColor: true,
66481
66536
  children: widgetPicker.level === "category" ? "Type to search; Enter to choose; Escape to go back" : "Type to search; Enter to add; Escape to go back"
66482
66537
  }, undefined, false, undefined, this),
66483
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66538
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66484
66539
  children: `Search: ${query}`
66485
66540
  }, undefined, false, undefined, this),
66486
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
66541
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
66487
66542
  marginTop: 1,
66488
66543
  flexDirection: "column",
66489
- children: widgetPicker.level === "category" && !topLevelSearch ? widgetCategories.map((category) => /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66544
+ children: widgetPicker.level === "category" && !topLevelSearch ? widgetCategories.map((category) => /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66490
66545
  ...category === widgetPicker.selectedCategory && { color: "green" },
66491
66546
  children: [
66492
66547
  category === widgetPicker.selectedCategory ? "▶ " : " ",
66493
66548
  category
66494
66549
  ]
66495
- }, category, true, undefined, this)) : entries.length ? entries.map((entry) => /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66550
+ }, category, true, undefined, this)) : entries.length ? entries.map((entry) => /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66496
66551
  ...entry.type === widgetPicker.selectedType && { color: "green" },
66497
66552
  children: [
66498
66553
  entry.type === widgetPicker.selectedType ? "▶ " : " ",
66499
66554
  entry.displayName
66500
66555
  ]
66501
- }, entry.type, true, undefined, this)) : /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66556
+ }, entry.type, true, undefined, this)) : /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66502
66557
  dimColor: true,
66503
66558
  children: "No widgets match this search."
66504
66559
  }, undefined, false, undefined, this)
@@ -66509,33 +66564,33 @@ function ItemsEditor({ widgets, onUpdate, onBack, lineNumber, settings: _setting
66509
66564
  const current = widgets[selectedIndex];
66510
66565
  const customLabels = customKeybindsFor(current ? getWidgetImpl(current.type) : null, current).map((entry) => entry.label).join(", ");
66511
66566
  const normalHelp = "↑↓ select, ←→ change, Enter move, (a)dd, (i)nsert, (d)elete, (k)opy, (c)lear, Escape back";
66512
- return /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
66567
+ return /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
66513
66568
  flexDirection: "column",
66514
66569
  children: [
66515
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66570
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66516
66571
  bold: true,
66517
66572
  children: [
66518
66573
  `Edit Line ${lineNumber}`,
66519
- moveMode && /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66574
+ moveMode && /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66520
66575
  color: "blue",
66521
66576
  children: " [MOVE MODE]"
66522
66577
  }, undefined, false, undefined, this)
66523
66578
  ]
66524
66579
  }, undefined, true, undefined, this),
66525
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66580
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66526
66581
  dimColor: true,
66527
66582
  children: moveMode ? "↑↓ to move, Escape or Enter to finish" : customLabels ? `${normalHelp}, ${customLabels}` : normalHelp
66528
66583
  }, undefined, false, undefined, this),
66529
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
66584
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
66530
66585
  marginTop: 1,
66531
66586
  flexDirection: "column",
66532
- children: widgets.length ? widgets.map((widget, index) => /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66587
+ children: widgets.length ? widgets.map((widget, index) => /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66533
66588
  ...index === selectedIndex && { color: "green" },
66534
66589
  children: [
66535
66590
  index === selectedIndex ? "▶ " : " ",
66536
66591
  rowLabel(widget)
66537
66592
  ]
66538
- }, widget.id, true, undefined, this)) : /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66593
+ }, widget.id, true, undefined, this)) : /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66539
66594
  dimColor: true,
66540
66595
  children: "No widgets yet. Press (a) to add one."
66541
66596
  }, undefined, false, undefined, this)
@@ -66594,17 +66649,17 @@ function cycleWidgetColor({ widgets, widgetId, direction, editingBackground, col
66594
66649
  }
66595
66650
 
66596
66651
  // src/tui/components/ColorMenu.tsx
66597
- var jsx_dev_runtime14 = __toESM(require_jsx_dev_runtime(), 1);
66652
+ var jsx_dev_runtime16 = __toESM(require_jsx_dev_runtime(), 1);
66598
66653
  function isTextInput(input2, key) {
66599
66654
  return Boolean(input2 && !key.ctrl && !key.meta && !key.tab);
66600
66655
  }
66601
66656
  function ColorMenu({ widgets, lineIndex, settings, onUpdate, onBack }) {
66602
- const [selectedIndex, setSelectedIndex] = import_react38.useState(0);
66603
- const [showSeparators, setShowSeparators] = import_react38.useState(false);
66604
- const [editingBackground, setEditingBackground] = import_react38.useState(false);
66605
- const [hexInput, setHexInput] = import_react38.useState(null);
66606
- const [ansiInput, setAnsiInput] = import_react38.useState(null);
66607
- const [clearConfirm, setClearConfirm] = import_react38.useState(false);
66657
+ const [selectedIndex, setSelectedIndex] = import_react44.useState(0);
66658
+ const [showSeparators, setShowSeparators] = import_react44.useState(false);
66659
+ const [editingBackground, setEditingBackground] = import_react44.useState(false);
66660
+ const [hexInput, setHexInput] = import_react44.useState(null);
66661
+ const [ansiInput, setAnsiInput] = import_react44.useState(null);
66662
+ const [clearConfirm, setClearConfirm] = import_react44.useState(false);
66608
66663
  const colorable = widgets.filter((widget) => widget.type !== "separator" && widget.type !== "flex-separator" || showSeparators);
66609
66664
  const selected = colorable[selectedIndex];
66610
66665
  const colors = getAvailableColorsForUI().map((entry) => entry.value);
@@ -66668,14 +66723,14 @@ function ColorMenu({ widgets, lineIndex, settings, onUpdate, onBack }) {
66668
66723
  }
66669
66724
  });
66670
66725
  if (clearConfirm) {
66671
- return /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
66726
+ return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
66672
66727
  flexDirection: "column",
66673
66728
  children: [
66674
- /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66729
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66675
66730
  bold: true,
66676
66731
  children: "Clear all widget styling?"
66677
66732
  }, undefined, false, undefined, this),
66678
- /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(ConfirmDialog, {
66733
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(ConfirmDialog, {
66679
66734
  inline: true,
66680
66735
  onConfirm: () => {
66681
66736
  onUpdate(clearAllWidgetStyling(widgets));
@@ -66687,14 +66742,14 @@ function ColorMenu({ widgets, lineIndex, settings, onUpdate, onBack }) {
66687
66742
  }, undefined, true, undefined, this);
66688
66743
  }
66689
66744
  if (!colorable.length) {
66690
- return /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
66745
+ return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
66691
66746
  flexDirection: "column",
66692
66747
  children: [
66693
- /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66748
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66694
66749
  bold: true,
66695
66750
  children: `Colors — Line ${lineIndex + 1}`
66696
66751
  }, undefined, false, undefined, this),
66697
- /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66752
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66698
66753
  dimColor: true,
66699
66754
  children: "No colorable widgets. Press Escape to go back."
66700
66755
  }, undefined, false, undefined, this)
@@ -66702,38 +66757,38 @@ function ColorMenu({ widgets, lineIndex, settings, onUpdate, onBack }) {
66702
66757
  }, undefined, true, undefined, this);
66703
66758
  }
66704
66759
  const inputMode = hexInput !== null ? `Hex: #${hexInput}` : ansiInput !== null ? `ANSI 256: ${ansiInput}` : null;
66705
- return /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
66760
+ return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
66706
66761
  flexDirection: "column",
66707
66762
  children: [
66708
- /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66763
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66709
66764
  bold: true,
66710
66765
  children: [
66711
66766
  `Colors — Line ${lineIndex + 1}`,
66712
- editingBackground && /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66767
+ editingBackground && /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66713
66768
  color: "yellow",
66714
66769
  children: " [Background]"
66715
66770
  }, undefined, false, undefined, this)
66716
66771
  ]
66717
66772
  }, undefined, true, undefined, this),
66718
- inputMode ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66773
+ inputMode ? /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66719
66774
  children: [
66720
66775
  inputMode,
66721
- /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66776
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66722
66777
  dimColor: true,
66723
66778
  children: " Enter to apply, Escape to cancel"
66724
66779
  }, undefined, false, undefined, this)
66725
66780
  ]
66726
- }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66781
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66727
66782
  dimColor: true,
66728
66783
  children: `↑↓ select, ←→ cycle ${editingBackground ? "background" : "foreground"}, (f)g/bg, (b)old, (d)im, (r)eset, (c)lear${settings.colorLevel === 3 ? ", (h)ex" : settings.colorLevel === 2 ? ", (a)nsi256" : ""}, Escape back`
66729
66784
  }, undefined, false, undefined, this),
66730
- /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
66785
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
66731
66786
  marginTop: 1,
66732
66787
  flexDirection: "column",
66733
66788
  children: colorable.map((widget, index) => {
66734
66789
  const label = displayWidgetType(widget.type);
66735
66790
  const styled = applyColors(label, widget.color, widget.backgroundColor, widget.bold, getColorLevelString(settings.colorLevel), widget.dim);
66736
- return /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66791
+ return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66737
66792
  ...index === selectedIndex && { color: "green" },
66738
66793
  children: [
66739
66794
  index === selectedIndex ? "▶ " : " ",
@@ -66742,7 +66797,7 @@ function ColorMenu({ widgets, lineIndex, settings, onUpdate, onBack }) {
66742
66797
  }, widget.id, true, undefined, this);
66743
66798
  })
66744
66799
  }, undefined, false, undefined, this),
66745
- !settings.powerline.enabled && !settings.defaultSeparator && /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66800
+ !settings.powerline.enabled && !settings.defaultSeparator && /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66746
66801
  dimColor: true,
66747
66802
  children: `(s)how separators: ${showSeparators ? "ON" : "OFF"}`
66748
66803
  }, undefined, false, undefined, this)
@@ -66751,13 +66806,13 @@ function ColorMenu({ widgets, lineIndex, settings, onUpdate, onBack }) {
66751
66806
  }
66752
66807
 
66753
66808
  // src/tui/components/ExportConfigDialog.tsx
66754
- var import_react39 = __toESM(require_react(), 1);
66755
- var jsx_dev_runtime15 = __toESM(require_jsx_dev_runtime(), 1);
66809
+ var import_react45 = __toESM(require_react(), 1);
66810
+ var jsx_dev_runtime17 = __toESM(require_jsx_dev_runtime(), 1);
66756
66811
  function acceptsText(input2, key) {
66757
66812
  return Boolean(input2 && !key.ctrl && !key.meta && !key.tab);
66758
66813
  }
66759
66814
  function ExportConfigDialog({ initialPath, onExport, onCancel }) {
66760
- const [path, setPath] = import_react39.useState(initialPath);
66815
+ const [path, setPath] = import_react45.useState(initialPath);
66761
66816
  use_input_default((input2, key) => {
66762
66817
  if (key.return)
66763
66818
  onExport(path);
@@ -66768,27 +66823,27 @@ function ExportConfigDialog({ initialPath, onExport, onCancel }) {
66768
66823
  else if (acceptsText(input2, key))
66769
66824
  setPath((current) => current + input2);
66770
66825
  });
66771
- return /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
66826
+ return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
66772
66827
  flexDirection: "column",
66773
66828
  children: [
66774
- /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66829
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
66775
66830
  bold: true,
66776
66831
  children: "Export Config"
66777
66832
  }, undefined, false, undefined, this),
66778
- /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66833
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
66779
66834
  dimColor: true,
66780
66835
  children: "Enter the file path to export your configuration to:"
66781
66836
  }, undefined, false, undefined, this),
66782
- /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66837
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
66783
66838
  children: [
66784
66839
  `Path: ${path}`,
66785
- /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66840
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
66786
66841
  inverse: true,
66787
66842
  children: " "
66788
66843
  }, undefined, false, undefined, this)
66789
66844
  ]
66790
66845
  }, undefined, true, undefined, this),
66791
- /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66846
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
66792
66847
  dimColor: true,
66793
66848
  children: "Enter to confirm, Escape to cancel"
66794
66849
  }, undefined, false, undefined, this)
@@ -66797,8 +66852,8 @@ function ExportConfigDialog({ initialPath, onExport, onCancel }) {
66797
66852
  }
66798
66853
 
66799
66854
  // src/tui/components/GlobalOverridesMenu.tsx
66800
- var import_react40 = __toESM(require_react(), 1);
66801
- var jsx_dev_runtime16 = __toESM(require_jsx_dev_runtime(), 1);
66855
+ var import_react46 = __toESM(require_react(), 1);
66856
+ var jsx_dev_runtime18 = __toESM(require_jsx_dev_runtime(), 1);
66802
66857
  function acceptsText2(input2, key) {
66803
66858
  return Boolean(input2 && !key.ctrl && !key.meta && !key.tab);
66804
66859
  }
@@ -66823,16 +66878,16 @@ function cycleGlobalNumberStyle(settings, kind) {
66823
66878
  };
66824
66879
  }
66825
66880
  function GlobalOverridesMenu({ settings, onUpdate, onBack }) {
66826
- const [editing, setEditing] = import_react40.useState(null);
66827
- const [value, setValue] = import_react40.useState("");
66828
- const [confirmSeparator, setConfirmSeparator] = import_react40.useState(false);
66829
- const [numberFormatMode, setNumberFormatMode] = import_react40.useState(false);
66830
- const [numberFormatKindIndex, setNumberFormatKindIndex] = import_react40.useState(0);
66831
- const [gradientMode, setGradientMode] = import_react40.useState(false);
66832
- const [gradientIndex, setGradientIndex] = import_react40.useState(0);
66833
- const [gradientStep, setGradientStep] = import_react40.useState(null);
66834
- const [gradientStart, setGradientStart] = import_react40.useState("");
66835
- const [gradientInput, setGradientInput] = import_react40.useState("");
66881
+ const [editing, setEditing] = import_react46.useState(null);
66882
+ const [value, setValue] = import_react46.useState("");
66883
+ const [confirmSeparator, setConfirmSeparator] = import_react46.useState(false);
66884
+ const [numberFormatMode, setNumberFormatMode] = import_react46.useState(false);
66885
+ const [numberFormatKindIndex, setNumberFormatKindIndex] = import_react46.useState(0);
66886
+ const [gradientMode, setGradientMode] = import_react46.useState(false);
66887
+ const [gradientIndex, setGradientIndex] = import_react46.useState(0);
66888
+ const [gradientStep, setGradientStep] = import_react46.useState(null);
66889
+ const [gradientStart, setGradientStart] = import_react46.useState("");
66890
+ const [gradientInput, setGradientInput] = import_react46.useState("");
66836
66891
  const foregrounds = getAvailableColorsForUI().map((entry) => entry.value);
66837
66892
  const backgrounds = getAvailableBackgroundColorsForUI().map((entry) => entry.value);
66838
66893
  const powerline = settings.powerline.enabled;
@@ -66961,14 +67016,14 @@ function GlobalOverridesMenu({ settings, onUpdate, onBack }) {
66961
67016
  }
66962
67017
  });
66963
67018
  if (confirmSeparator) {
66964
- return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
67019
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
66965
67020
  flexDirection: "column",
66966
67021
  children: [
66967
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67022
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66968
67023
  color: "yellow",
66969
67024
  children: "Setting a default separator removes manual separators. Continue?"
66970
67025
  }, undefined, false, undefined, this),
66971
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(ConfirmDialog, {
67026
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(ConfirmDialog, {
66972
67027
  inline: true,
66973
67028
  onConfirm: () => {
66974
67029
  onUpdate({ ...settings, defaultSeparator: value, lines: settings.lines.map((line3) => line3.filter((item) => item.type !== "separator")) });
@@ -66985,30 +67040,30 @@ function GlobalOverridesMenu({ settings, onUpdate, onBack }) {
66985
67040
  }
66986
67041
  if (gradientMode) {
66987
67042
  if (gradientStep) {
66988
- return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
67043
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
66989
67044
  flexDirection: "column",
66990
67045
  children: [
66991
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67046
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66992
67047
  bold: true,
66993
67048
  children: "Custom Gradient — Override FG Color"
66994
67049
  }, undefined, false, undefined, this),
66995
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67050
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66996
67051
  children: gradientStep === "start" ? "Enter START hex color:" : "Enter END hex color:"
66997
67052
  }, undefined, false, undefined, this),
66998
- gradientStep === "end" && /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67053
+ gradientStep === "end" && /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66999
67054
  dimColor: true,
67000
67055
  children: `Start: #${gradientStart}`
67001
67056
  }, undefined, false, undefined, this),
67002
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67057
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67003
67058
  children: [
67004
67059
  `#${gradientInput}`,
67005
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67060
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67006
67061
  dimColor: true,
67007
67062
  children: "_".repeat(6 - gradientInput.length)
67008
67063
  }, undefined, false, undefined, this)
67009
67064
  ]
67010
67065
  }, undefined, true, undefined, this),
67011
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67066
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67012
67067
  dimColor: true,
67013
67068
  children: "Enter to continue, Escape to go back"
67014
67069
  }, undefined, false, undefined, this)
@@ -67016,28 +67071,28 @@ function GlobalOverridesMenu({ settings, onUpdate, onBack }) {
67016
67071
  }, undefined, true, undefined, this);
67017
67072
  }
67018
67073
  const level = getColorLevelString(settings.colorLevel);
67019
- return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
67074
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
67020
67075
  flexDirection: "column",
67021
67076
  children: [
67022
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67077
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67023
67078
  bold: true,
67024
67079
  children: "Select Gradient — Override FG Color"
67025
67080
  }, undefined, false, undefined, this),
67026
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67081
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67027
67082
  dimColor: true,
67028
67083
  children: "↑↓ select, Enter apply, Escape cancel"
67029
67084
  }, undefined, false, undefined, this),
67030
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
67085
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
67031
67086
  marginTop: 1,
67032
67087
  flexDirection: "column",
67033
67088
  children: [
67034
- GRADIENT_PRESET_NAMES.map((name, index) => /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67089
+ GRADIENT_PRESET_NAMES.map((name, index) => /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67035
67090
  children: [
67036
67091
  index === gradientIndex ? "▶ " : " ",
67037
67092
  applyColors(name, `gradient:${name}`, undefined, index === gradientIndex, level)
67038
67093
  ]
67039
67094
  }, name, true, undefined, this)),
67040
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67095
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67041
67096
  children: [
67042
67097
  gradientIndex === GRADIENT_PRESET_NAMES.length ? "▶ " : " ",
67043
67098
  "Custom (two hex stops)"
@@ -67050,23 +67105,23 @@ function GlobalOverridesMenu({ settings, onUpdate, onBack }) {
67050
67105
  }
67051
67106
  if (numberFormatMode) {
67052
67107
  const width = Math.max(...NUMBER_KINDS.map((kind) => kind.length));
67053
- return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
67108
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
67054
67109
  flexDirection: "column",
67055
67110
  children: [
67056
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67111
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67057
67112
  bold: true,
67058
67113
  children: "Global Number Formatting"
67059
67114
  }, undefined, false, undefined, this),
67060
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67115
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67061
67116
  dimColor: true,
67062
67117
  children: "↑↓ to select a number type, ←→ to cycle its style, ESC to go back"
67063
67118
  }, undefined, false, undefined, this),
67064
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
67119
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
67065
67120
  marginTop: 1,
67066
67121
  flexDirection: "column",
67067
67122
  children: NUMBER_KINDS.map((kind, idx) => {
67068
67123
  const style = settings.numberFormat?.[kind]?.style ?? "precise (default)";
67069
- return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67124
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67070
67125
  ...idx === numberFormatKindIndex && { color: "cyan" },
67071
67126
  children: [
67072
67127
  idx === numberFormatKindIndex ? "▶ " : " ",
@@ -67077,15 +67132,15 @@ function GlobalOverridesMenu({ settings, onUpdate, onBack }) {
67077
67132
  }, kind, true, undefined, this);
67078
67133
  })
67079
67134
  }, undefined, false, undefined, this),
67080
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
67135
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
67081
67136
  marginTop: 1,
67082
67137
  flexDirection: "column",
67083
67138
  children: [
67084
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67139
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67085
67140
  dimColor: true,
67086
67141
  children: "precise = keep trailing zeros (1.0M), compact = trim them (1M / 1.1M), whole = no decimals (1M)."
67087
67142
  }, undefined, false, undefined, this),
67088
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67143
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67089
67144
  dimColor: true,
67090
67145
  children: "A global style forces that type across every widget. Decimal places are set per-widget or in settings.json."
67091
67146
  }, undefined, false, undefined, this)
@@ -67095,68 +67150,68 @@ function GlobalOverridesMenu({ settings, onUpdate, onBack }) {
67095
67150
  }, undefined, true, undefined, this);
67096
67151
  }
67097
67152
  if (editing) {
67098
- return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
67153
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
67099
67154
  flexDirection: "column",
67100
67155
  children: [
67101
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67156
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67102
67157
  bold: true,
67103
67158
  children: editing === "padding" ? "Default Padding" : "Default Separator"
67104
67159
  }, undefined, false, undefined, this),
67105
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67160
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67106
67161
  children: [
67107
67162
  value,
67108
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67163
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67109
67164
  inverse: true,
67110
67165
  children: " "
67111
67166
  }, undefined, false, undefined, this)
67112
67167
  ]
67113
67168
  }, undefined, true, undefined, this),
67114
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67169
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67115
67170
  dimColor: true,
67116
67171
  children: "Enter to apply, Escape to cancel"
67117
67172
  }, undefined, false, undefined, this)
67118
67173
  ]
67119
67174
  }, undefined, true, undefined, this);
67120
67175
  }
67121
- return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
67176
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
67122
67177
  flexDirection: "column",
67123
67178
  children: [
67124
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67179
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67125
67180
  bold: true,
67126
67181
  children: "Global Overrides"
67127
67182
  }, undefined, false, undefined, this),
67128
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67183
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67129
67184
  dimColor: true,
67130
67185
  children: "Configure rendering-wide padding, separators, and styling."
67131
67186
  }, undefined, false, undefined, this),
67132
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67187
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67133
67188
  children: `Global Bold: ${settings.globalBold ? "Enabled" : "Disabled"} (o)`
67134
67189
  }, undefined, false, undefined, this),
67135
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67190
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67136
67191
  children: `Minimalist Mode: ${settings.minimalistMode ? "Enabled" : "Disabled"} (m)`
67137
67192
  }, undefined, false, undefined, this),
67138
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67193
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67139
67194
  children: `Number Formatting: ${settings.numberFormat ? "customized" : "(defaults)"} (n)`
67140
67195
  }, undefined, false, undefined, this),
67141
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67196
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67142
67197
  children: `Default Padding: ${settings.defaultPadding ? JSON.stringify(settings.defaultPadding) : "none"} (p)`
67143
67198
  }, undefined, false, undefined, this),
67144
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67199
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67145
67200
  children: `Padding Side: ${settings.defaultPaddingSide} (d)`
67146
67201
  }, undefined, false, undefined, this),
67147
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67202
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67148
67203
  children: `Override FG: ${settings.overrideForegroundColor ?? "none"} (f cycle, g gradient, x clear)`
67149
67204
  }, undefined, false, undefined, this),
67150
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67205
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67151
67206
  children: powerline ? "Override BG: disabled while Powerline is active" : `Override BG: ${settings.overrideBackgroundColor ?? "none"} (b cycle, c clear)`
67152
67207
  }, undefined, false, undefined, this),
67153
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67208
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67154
67209
  children: powerline ? "Default Separator: disabled while Powerline is active" : `Default Separator: ${settings.defaultSeparator ? JSON.stringify(settings.defaultSeparator) : "none"} (s)`
67155
67210
  }, undefined, false, undefined, this),
67156
- !powerline && /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67211
+ !powerline && /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67157
67212
  children: `Inherit Separator Colors: ${settings.inheritSeparatorColors ? "Enabled" : "Disabled"} (i)`
67158
67213
  }, undefined, false, undefined, this),
67159
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67214
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67160
67215
  dimColor: true,
67161
67216
  children: "Escape to cancel these changes"
67162
67217
  }, undefined, false, undefined, this)
@@ -67165,13 +67220,13 @@ function GlobalOverridesMenu({ settings, onUpdate, onBack }) {
67165
67220
  }
67166
67221
 
67167
67222
  // src/tui/components/ImportConfigDialog.tsx
67168
- var import_react41 = __toESM(require_react(), 1);
67169
- var jsx_dev_runtime17 = __toESM(require_jsx_dev_runtime(), 1);
67223
+ var import_react47 = __toESM(require_react(), 1);
67224
+ var jsx_dev_runtime19 = __toESM(require_jsx_dev_runtime(), 1);
67170
67225
  function acceptsText3(input2, key) {
67171
67226
  return Boolean(input2 && !key.ctrl && !key.meta && !key.tab);
67172
67227
  }
67173
67228
  function ImportConfigDialog({ error: error61, onFileChosen, onCancel }) {
67174
- const [path, setPath] = import_react41.useState("");
67229
+ const [path, setPath] = import_react47.useState("");
67175
67230
  use_input_default((input2, key) => {
67176
67231
  if (key.return)
67177
67232
  onFileChosen(path);
@@ -67182,31 +67237,31 @@ function ImportConfigDialog({ error: error61, onFileChosen, onCancel }) {
67182
67237
  else if (acceptsText3(input2, key))
67183
67238
  setPath((current) => current + input2);
67184
67239
  });
67185
- return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
67240
+ return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
67186
67241
  flexDirection: "column",
67187
67242
  children: [
67188
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
67243
+ /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67189
67244
  bold: true,
67190
67245
  children: "Import Config"
67191
67246
  }, undefined, false, undefined, this),
67192
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
67247
+ /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67193
67248
  dimColor: true,
67194
67249
  children: "Enter the file path to import configuration from:"
67195
67250
  }, undefined, false, undefined, this),
67196
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
67251
+ /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67197
67252
  children: [
67198
67253
  `Path: ${path}`,
67199
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
67254
+ /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67200
67255
  inverse: true,
67201
67256
  children: " "
67202
67257
  }, undefined, false, undefined, this)
67203
67258
  ]
67204
67259
  }, undefined, true, undefined, this),
67205
- error61 && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
67260
+ error61 && /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67206
67261
  color: "red",
67207
67262
  children: error61
67208
67263
  }, undefined, false, undefined, this),
67209
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
67264
+ /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67210
67265
  dimColor: true,
67211
67266
  children: "Enter to preview, Escape to cancel"
67212
67267
  }, undefined, false, undefined, this)
@@ -67215,7 +67270,7 @@ function ImportConfigDialog({ error: error61, onFileChosen, onCancel }) {
67215
67270
  }
67216
67271
 
67217
67272
  // src/tui/components/StatusLinePreview.tsx
67218
- var jsx_dev_runtime18 = __toESM(require_jsx_dev_runtime(), 1);
67273
+ var jsx_dev_runtime20 = __toESM(require_jsx_dev_runtime(), 1);
67219
67274
  var PREVIEW_CONTEXT = {
67220
67275
  data: { payload_version: 1 },
67221
67276
  now: new Date(0),
@@ -67223,78 +67278,78 @@ var PREVIEW_CONTEXT = {
67223
67278
  };
67224
67279
  function StatusLinePreview({ settings, terminalWidth }) {
67225
67280
  const rows = renderStatusLines(settings, { ...PREVIEW_CONTEXT, isPreview: true, terminalWidth });
67226
- return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
67281
+ return /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
67227
67282
  flexDirection: "column",
67228
- children: rows.map((row, i) => /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67283
+ children: rows.map((row, i) => /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
67229
67284
  children: row
67230
67285
  }, i, false, undefined, this))
67231
67286
  }, undefined, false, undefined, this);
67232
67287
  }
67233
67288
 
67234
67289
  // src/tui/components/ImportPreviewDialog.tsx
67235
- var jsx_dev_runtime19 = __toESM(require_jsx_dev_runtime(), 1);
67290
+ var jsx_dev_runtime21 = __toESM(require_jsx_dev_runtime(), 1);
67236
67291
  function ImportPreviewDialog({ preview, terminalWidth, busy = false, onConfirm, onCancel }) {
67237
67292
  const rows = renderStatusLines(preview.settings, { ...PREVIEW_CONTEXT, isPreview: true, terminalWidth });
67238
67293
  const allCustomCommands = preview.settings.lines.flat().filter((item) => item.type === "custom-command");
67239
67294
  const uncachedCommands = allCustomCommands.filter((item) => item.refreshMs === undefined).map((item) => item.commandPath ?? "(no command)");
67240
67295
  const cachedCommands = allCustomCommands.filter((item) => item.refreshMs !== undefined).map((item) => `${item.commandPath ?? "(no command)"} (every ${item.refreshMs}ms)`);
67241
- return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
67296
+ return /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Box_default, {
67242
67297
  flexDirection: "column",
67243
67298
  children: [
67244
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67299
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
67245
67300
  bold: true,
67246
67301
  children: "Import Preview"
67247
67302
  }, undefined, false, undefined, this),
67248
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67303
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
67249
67304
  dimColor: true,
67250
67305
  children: "Preview rendered by the production statusline renderer:"
67251
67306
  }, undefined, false, undefined, this),
67252
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
67307
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Box_default, {
67253
67308
  marginTop: 1,
67254
67309
  flexDirection: "column",
67255
- children: rows.map((row, index) => /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67310
+ children: rows.map((row, index) => /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
67256
67311
  children: row
67257
67312
  }, index, false, undefined, this))
67258
67313
  }, undefined, false, undefined, this),
67259
- preview.omittedTypes.length > 0 && /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67314
+ preview.omittedTypes.length > 0 && /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
67260
67315
  color: "yellow",
67261
67316
  children: `Deferred unsupported widgets: ${preview.omittedTypes.join(", ")}`
67262
67317
  }, undefined, false, undefined, this),
67263
- uncachedCommands.length > 0 && /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
67318
+ uncachedCommands.length > 0 && /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Box_default, {
67264
67319
  flexDirection: "column",
67265
67320
  children: [
67266
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67321
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
67267
67322
  color: "yellow",
67268
67323
  children: "Commands that will run on every render:"
67269
67324
  }, undefined, false, undefined, this),
67270
- uncachedCommands.map((command, index) => /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67325
+ uncachedCommands.map((command, index) => /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
67271
67326
  color: "yellow",
67272
67327
  children: ` ${command}`
67273
67328
  }, index, false, undefined, this))
67274
67329
  ]
67275
67330
  }, undefined, true, undefined, this),
67276
- cachedCommands.length > 0 && /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
67331
+ cachedCommands.length > 0 && /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Box_default, {
67277
67332
  flexDirection: "column",
67278
67333
  children: [
67279
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67334
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
67280
67335
  color: "yellow",
67281
67336
  children: "Cached commands (run in background):"
67282
67337
  }, undefined, false, undefined, this),
67283
- cachedCommands.map((command, index) => /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67338
+ cachedCommands.map((command, index) => /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
67284
67339
  color: "yellow",
67285
67340
  children: ` ${command}`
67286
67341
  }, index, false, undefined, this))
67287
67342
  ]
67288
67343
  }, undefined, true, undefined, this),
67289
- busy ? /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67344
+ busy ? /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
67290
67345
  dimColor: true,
67291
67346
  children: "Applying imported configuration…"
67292
- }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(jsx_dev_runtime19.Fragment, {
67347
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(jsx_dev_runtime21.Fragment, {
67293
67348
  children: [
67294
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67349
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
67295
67350
  children: "Apply this preset?"
67296
67351
  }, undefined, false, undefined, this),
67297
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(ConfirmDialog, {
67352
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(ConfirmDialog, {
67298
67353
  inline: true,
67299
67354
  onConfirm,
67300
67355
  onCancel
@@ -67306,8 +67361,8 @@ function ImportPreviewDialog({ preview, terminalWidth, busy = false, onConfirm,
67306
67361
  }
67307
67362
 
67308
67363
  // src/tui/components/LineSelector.tsx
67309
- var import_react42 = __toESM(require_react(), 1);
67310
- var jsx_dev_runtime20 = __toESM(require_jsx_dev_runtime(), 1);
67364
+ var import_react48 = __toESM(require_react(), 1);
67365
+ var jsx_dev_runtime22 = __toESM(require_jsx_dev_runtime(), 1);
67311
67366
  function cloneLines(lines) {
67312
67367
  return lines.map((line3) => line3.map((item) => ({ ...item, ...item.metadata && { metadata: { ...item.metadata } } })));
67313
67368
  }
@@ -67323,12 +67378,12 @@ function LineSelector({
67323
67378
  title = "Edit Lines",
67324
67379
  allowEditing = false
67325
67380
  }) {
67326
- const [selectedIndex, setSelectedIndex] = import_react42.useState(initialSelection);
67327
- const [localLines, setLocalLines] = import_react42.useState(() => cloneLines(lines));
67328
- const [moveMode, setMoveMode] = import_react42.useState(false);
67329
- const [confirmDelete, setConfirmDelete] = import_react42.useState(false);
67330
- const [limitMessage, setLimitMessage] = import_react42.useState(null);
67331
- import_react42.useEffect(() => {
67381
+ const [selectedIndex, setSelectedIndex] = import_react48.useState(initialSelection);
67382
+ const [localLines, setLocalLines] = import_react48.useState(() => cloneLines(lines));
67383
+ const [moveMode, setMoveMode] = import_react48.useState(false);
67384
+ const [confirmDelete, setConfirmDelete] = import_react48.useState(false);
67385
+ const [limitMessage, setLimitMessage] = import_react48.useState(null);
67386
+ import_react48.useEffect(() => {
67332
67387
  setLocalLines(cloneLines(lines));
67333
67388
  setSelectedIndex((current) => Math.min(current, Math.max(0, lines.length - 1)));
67334
67389
  }, [lines]);
@@ -67380,18 +67435,18 @@ function LineSelector({
67380
67435
  onBack();
67381
67436
  });
67382
67437
  if (confirmDelete) {
67383
- return /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
67438
+ return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
67384
67439
  flexDirection: "column",
67385
67440
  children: [
67386
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
67441
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67387
67442
  bold: true,
67388
67443
  children: `Delete Line ${selectedIndex + 1}?`
67389
67444
  }, undefined, false, undefined, this),
67390
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
67445
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67391
67446
  dimColor: true,
67392
67447
  children: lineSummary(localLines[selectedIndex] ?? [])
67393
67448
  }, undefined, false, undefined, this),
67394
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(ConfirmDialog, {
67449
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(ConfirmDialog, {
67395
67450
  inline: true,
67396
67451
  onConfirm: () => {
67397
67452
  const next = localLines.filter((_2, index) => index !== selectedIndex);
@@ -67405,28 +67460,28 @@ function LineSelector({
67405
67460
  }, undefined, true, undefined, this);
67406
67461
  }
67407
67462
  if (moveMode) {
67408
- return /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
67463
+ return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
67409
67464
  flexDirection: "column",
67410
67465
  children: [
67411
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
67466
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67412
67467
  bold: true,
67413
67468
  children: [
67414
67469
  title,
67415
67470
  " ",
67416
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
67471
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67417
67472
  color: "blue",
67418
67473
  children: "[MOVE MODE]"
67419
67474
  }, undefined, false, undefined, this)
67420
67475
  ]
67421
67476
  }, undefined, true, undefined, this),
67422
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
67477
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67423
67478
  dimColor: true,
67424
67479
  children: "↑↓ to move a line, Escape or Enter to finish"
67425
67480
  }, undefined, false, undefined, this),
67426
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
67481
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
67427
67482
  marginTop: 1,
67428
67483
  flexDirection: "column",
67429
- children: localLines.map((line3, index) => /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
67484
+ children: localLines.map((line3, index) => /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67430
67485
  ...index === selectedIndex && { color: "green" },
67431
67486
  children: [
67432
67487
  index === selectedIndex ? "◆ " : " ",
@@ -67437,22 +67492,22 @@ function LineSelector({
67437
67492
  ]
67438
67493
  }, undefined, true, undefined, this);
67439
67494
  }
67440
- return /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
67495
+ return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
67441
67496
  flexDirection: "column",
67442
67497
  children: [
67443
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
67498
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67444
67499
  bold: true,
67445
67500
  children: title
67446
67501
  }, undefined, false, undefined, this),
67447
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
67502
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67448
67503
  dimColor: true,
67449
67504
  children: allowEditing ? "Enter to edit; (a)dd, (d)elete, (m)ove; Escape to cancel" : "Enter to choose a line; Escape to cancel"
67450
67505
  }, undefined, false, undefined, this),
67451
- limitMessage && /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
67506
+ limitMessage && /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67452
67507
  color: "yellow",
67453
67508
  children: limitMessage
67454
67509
  }, undefined, false, undefined, this),
67455
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(List, {
67510
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(List, {
67456
67511
  marginTop: 1,
67457
67512
  items: localLines.map((line3, index) => ({ label: `Line ${index + 1}`, sublabel: `(${lineSummary(line3)})`, value: index })),
67458
67513
  initialSelection: selectedIndex,
@@ -67465,7 +67520,7 @@ function LineSelector({
67465
67520
  }
67466
67521
 
67467
67522
  // src/tui/components/MainMenu.tsx
67468
- var jsx_dev_runtime21 = __toESM(require_jsx_dev_runtime(), 1);
67523
+ var jsx_dev_runtime23 = __toESM(require_jsx_dev_runtime(), 1);
67469
67524
  function buildMainMenuItems() {
67470
67525
  return [
67471
67526
  { label: "Lines", value: "lines", description: "Edit up to three status-line rows and their widgets." },
@@ -67481,17 +67536,17 @@ function buildMainMenuItems() {
67481
67536
  ];
67482
67537
  }
67483
67538
  function MainMenu({ onSelect, initialSelection = 0, hasChanges = false }) {
67484
- return /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Box_default, {
67539
+ return /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Box_default, {
67485
67540
  flexDirection: "column",
67486
67541
  children: [
67487
- /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
67542
+ /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text, {
67488
67543
  bold: true,
67489
67544
  children: [
67490
67545
  "Main Menu",
67491
67546
  hasChanges ? " (unsaved changes)" : ""
67492
67547
  ]
67493
67548
  }, undefined, true, undefined, this),
67494
- /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(List, {
67549
+ /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(List, {
67495
67550
  items: buildMainMenuItems(),
67496
67551
  marginTop: 1,
67497
67552
  initialSelection,
@@ -67507,8 +67562,8 @@ function MainMenu({ onSelect, initialSelection = 0, hasChanges = false }) {
67507
67562
  // src/tui/components/PowerlineSetup.tsx
67508
67563
  import { existsSync as existsSync16, readdirSync as readdirSync5 } from "node:fs";
67509
67564
  import { homedir as homedir2, platform as platform2 } from "node:os";
67510
- import { join as join23 } from "node:path";
67511
- var import_react45 = __toESM(require_react(), 1);
67565
+ import { join as join22 } from "node:path";
67566
+ var import_react51 = __toESM(require_react(), 1);
67512
67567
 
67513
67568
  // src/utils/powerline-settings.ts
67514
67569
  function resolveEnabledPowerlineTheme(theme) {
@@ -67535,8 +67590,8 @@ function buildEnabledPowerlineSettings(settings, removeManualSeparators) {
67535
67590
  }
67536
67591
 
67537
67592
  // src/tui/components/PowerlineSeparatorEditor.tsx
67538
- var import_react43 = __toESM(require_react(), 1);
67539
- var jsx_dev_runtime22 = __toESM(require_jsx_dev_runtime(), 1);
67593
+ var import_react49 = __toESM(require_react(), 1);
67594
+ var jsx_dev_runtime24 = __toESM(require_jsx_dev_runtime(), 1);
67540
67595
  var PRESETS = {
67541
67596
  separator: [
67542
67597
  { char: "", name: "Triangle Right" },
@@ -67575,8 +67630,8 @@ function PowerlineSeparatorEditor({ settings, mode, onUpdate, onBack }) {
67575
67630
  const items = itemsFor(settings, mode);
67576
67631
  const presets = PRESETS[mode];
67577
67632
  const inversions = mode === "separator" ? settings.powerline.separatorInvertBackground : [];
67578
- const [selectedIndex, setSelectedIndex] = import_react43.useState(0);
67579
- const [hexInput, setHexInput] = import_react43.useState(null);
67633
+ const [selectedIndex, setSelectedIndex] = import_react49.useState(0);
67634
+ const [hexInput, setHexInput] = import_react49.useState(null);
67580
67635
  const update2 = (nextItems, nextInversions = inversions) => {
67581
67636
  const powerline = mode === "separator" ? { ...settings.powerline, separators: nextItems, separatorInvertBackground: nextInversions } : mode === "startCap" ? { ...settings.powerline, startCaps: nextItems } : { ...settings.powerline, endCaps: nextItems };
67582
67637
  onUpdate({ ...settings, powerline });
@@ -67646,55 +67701,55 @@ function PowerlineSeparatorEditor({ settings, mode, onUpdate, onBack }) {
67646
67701
  }
67647
67702
  });
67648
67703
  if (hexInput !== null) {
67649
- return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
67704
+ return /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Box_default, {
67650
67705
  flexDirection: "column",
67651
67706
  children: [
67652
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67707
+ /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
67653
67708
  bold: true,
67654
67709
  children: titleFor(mode)
67655
67710
  }, undefined, false, undefined, this),
67656
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67711
+ /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
67657
67712
  children: [
67658
67713
  `U+${hexInput}`,
67659
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67714
+ /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
67660
67715
  inverse: true,
67661
67716
  children: " "
67662
67717
  }, undefined, false, undefined, this)
67663
67718
  ]
67664
67719
  }, undefined, true, undefined, this),
67665
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67720
+ /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
67666
67721
  dimColor: true,
67667
67722
  children: "Enter 4–6 hexadecimal digits, Escape to cancel"
67668
67723
  }, undefined, false, undefined, this)
67669
67724
  ]
67670
67725
  }, undefined, true, undefined, this);
67671
67726
  }
67672
- return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
67727
+ return /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Box_default, {
67673
67728
  flexDirection: "column",
67674
67729
  children: [
67675
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67730
+ /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
67676
67731
  bold: true,
67677
67732
  children: titleFor(mode)
67678
67733
  }, undefined, false, undefined, this),
67679
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67734
+ /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
67680
67735
  dimColor: true,
67681
67736
  children: `↑↓ select, ←→ cycle, (a)dd, (i)nsert${mode !== "separator" || items.length > 1 ? ", (d)elete" : ""}, (c)lear, (h)ex${mode === "separator" ? ", (t)oggle invert" : ""}, Escape back`
67682
67737
  }, undefined, false, undefined, this),
67683
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
67738
+ /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Box_default, {
67684
67739
  marginTop: 1,
67685
67740
  flexDirection: "column",
67686
67741
  children: items.length ? items.map((item, index) => {
67687
67742
  const preset = presets.find((entry) => entry.char === item);
67688
67743
  const code = item.codePointAt(0)?.toString(16).toUpperCase().padStart(4, "0");
67689
67744
  const label = preset ? `${item} - ${preset.name}` : `${item} - Custom (U+${code})`;
67690
- return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67745
+ return /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
67691
67746
  ...index === selected && { color: "green" },
67692
67747
  children: [
67693
67748
  index === selected ? "▶ " : " ",
67694
67749
  `${index + 1}: ${label}${mode === "separator" && inversions[index] ? " [Inverted]" : ""}`
67695
67750
  ]
67696
67751
  }, `${item}-${index}`, true, undefined, this);
67697
- }) : /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67752
+ }) : /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
67698
67753
  dimColor: true,
67699
67754
  children: "(none configured — press a to add)"
67700
67755
  }, undefined, false, undefined, this)
@@ -67704,8 +67759,8 @@ function PowerlineSeparatorEditor({ settings, mode, onUpdate, onBack }) {
67704
67759
  }
67705
67760
 
67706
67761
  // src/tui/components/PowerlineThemeSelector.tsx
67707
- var import_react44 = __toESM(require_react(), 1);
67708
- var jsx_dev_runtime23 = __toESM(require_jsx_dev_runtime(), 1);
67762
+ var import_react50 = __toESM(require_react(), 1);
67763
+ var jsx_dev_runtime25 = __toESM(require_jsx_dev_runtime(), 1);
67709
67764
  function buildPowerlineThemeItems(themes, originalTheme) {
67710
67765
  return themes.map((themeName) => {
67711
67766
  const theme = getPowerlineTheme(themeName);
@@ -67744,17 +67799,17 @@ function applyCustomPowerlineTheme(settings, themeName) {
67744
67799
  };
67745
67800
  }
67746
67801
  function PowerlineThemeSelector({ settings, onUpdate, onBack }) {
67747
- const themes = import_react44.useMemo(() => getPowerlineThemes(), []);
67748
- const originalSettings = import_react44.useRef(settings);
67749
- const originalTheme = import_react44.useRef(settings.powerline.theme ?? "custom");
67750
- const [selectedIndex, setSelectedIndex] = import_react44.useState(Math.max(0, themes.indexOf(originalTheme.current)));
67751
- const [confirmCustom, setConfirmCustom] = import_react44.useState(false);
67752
- const latest = import_react44.useRef({ settings, onUpdate });
67753
- const initialized = import_react44.useRef(false);
67754
- import_react44.useEffect(() => {
67802
+ const themes = import_react50.useMemo(() => getPowerlineThemes(), []);
67803
+ const originalSettings = import_react50.useRef(settings);
67804
+ const originalTheme = import_react50.useRef(settings.powerline.theme ?? "custom");
67805
+ const [selectedIndex, setSelectedIndex] = import_react50.useState(Math.max(0, themes.indexOf(originalTheme.current)));
67806
+ const [confirmCustom, setConfirmCustom] = import_react50.useState(false);
67807
+ const latest = import_react50.useRef({ settings, onUpdate });
67808
+ const initialized = import_react50.useRef(false);
67809
+ import_react50.useEffect(() => {
67755
67810
  latest.current = { settings, onUpdate };
67756
67811
  }, [settings, onUpdate]);
67757
- import_react44.useEffect(() => {
67812
+ import_react50.useEffect(() => {
67758
67813
  const theme = themes[selectedIndex];
67759
67814
  if (!theme || !initialized.current) {
67760
67815
  initialized.current = true;
@@ -67776,21 +67831,21 @@ function PowerlineThemeSelector({ settings, onUpdate, onBack }) {
67776
67831
  });
67777
67832
  const selectedTheme = themes[selectedIndex];
67778
67833
  if (confirmCustom) {
67779
- return /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Box_default, {
67834
+ return /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Box_default, {
67780
67835
  flexDirection: "column",
67781
67836
  children: [
67782
- /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text, {
67837
+ /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
67783
67838
  bold: true,
67784
67839
  color: "yellow",
67785
67840
  children: "Confirm Customization"
67786
67841
  }, undefined, false, undefined, this),
67787
- /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text, {
67842
+ /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
67788
67843
  children: "This copies the current theme colors to widgets and overwrites existing widget colors."
67789
67844
  }, undefined, false, undefined, this),
67790
- /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text, {
67845
+ /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
67791
67846
  children: "Continue?"
67792
67847
  }, undefined, false, undefined, this),
67793
- /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(ConfirmDialog, {
67848
+ /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(ConfirmDialog, {
67794
67849
  inline: true,
67795
67850
  onConfirm: () => {
67796
67851
  if (selectedTheme) {
@@ -67806,24 +67861,24 @@ function PowerlineThemeSelector({ settings, onUpdate, onBack }) {
67806
67861
  ]
67807
67862
  }, undefined, true, undefined, this);
67808
67863
  }
67809
- return /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Box_default, {
67864
+ return /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Box_default, {
67810
67865
  flexDirection: "column",
67811
67866
  children: [
67812
- /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text, {
67867
+ /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
67813
67868
  bold: true,
67814
67869
  children: [
67815
67870
  "Powerline Theme Selection ",
67816
- /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text, {
67871
+ /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
67817
67872
  dimColor: true,
67818
67873
  children: `| Original: ${originalTheme.current}`
67819
67874
  }, undefined, false, undefined, this)
67820
67875
  ]
67821
67876
  }, undefined, true, undefined, this),
67822
- /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text, {
67877
+ /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
67823
67878
  dimColor: true,
67824
67879
  children: `↑↓ navigate, Enter apply${selectedTheme && selectedTheme !== "custom" ? ", (c)ustomize theme" : ""}, Escape cancel`
67825
67880
  }, undefined, false, undefined, this),
67826
- /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(List, {
67881
+ /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(List, {
67827
67882
  marginTop: 1,
67828
67883
  items: buildPowerlineThemeItems(themes, originalTheme.current),
67829
67884
  initialSelection: selectedIndex,
@@ -67833,7 +67888,7 @@ function PowerlineThemeSelector({ settings, onUpdate, onBack }) {
67833
67888
  },
67834
67889
  onSelect: () => onBack()
67835
67890
  }, undefined, false, undefined, this),
67836
- settings.colorLevel === 1 && /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text, {
67891
+ settings.colorLevel === 1 && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
67837
67892
  color: "yellow",
67838
67893
  children: "16-color themes have a limited palette."
67839
67894
  }, undefined, false, undefined, this)
@@ -67842,7 +67897,7 @@ function PowerlineThemeSelector({ settings, onUpdate, onBack }) {
67842
67897
  }
67843
67898
 
67844
67899
  // src/tui/components/PowerlineSetup.tsx
67845
- var jsx_dev_runtime24 = __toESM(require_jsx_dev_runtime(), 1);
67900
+ var jsx_dev_runtime26 = __toESM(require_jsx_dev_runtime(), 1);
67846
67901
  var SEPARATORS = [
67847
67902
  { char: "", name: "Triangle Right" },
67848
67903
  { char: "", name: "Triangle Left" },
@@ -67892,7 +67947,7 @@ function buildPowerlineSetupMenuItems(powerline) {
67892
67947
  ];
67893
67948
  }
67894
67949
  function detectPowerlineFont() {
67895
- const dirs = platform2() === "darwin" ? [join23(homedir2(), "Library", "Fonts"), "/Library/Fonts"] : platform2() === "win32" ? [join23(homedir2(), "AppData", "Local", "Microsoft", "Windows", "Fonts"), "C:\\Windows\\Fonts"] : [join23(homedir2(), ".local", "share", "fonts"), join23(homedir2(), ".fonts"), "/usr/share/fonts"];
67950
+ const dirs = platform2() === "darwin" ? [join22(homedir2(), "Library", "Fonts"), "/Library/Fonts"] : platform2() === "win32" ? [join22(homedir2(), "AppData", "Local", "Microsoft", "Windows", "Fonts"), "C:\\Windows\\Fonts"] : [join22(homedir2(), ".local", "share", "fonts"), join22(homedir2(), ".fonts"), "/usr/share/fonts"];
67896
67951
  try {
67897
67952
  return dirs.some((dir) => existsSync16(dir) && readdirSync5(dir).some((file2) => /powerline|nerd font|meslo.*lg/i.test(file2)));
67898
67953
  } catch {
@@ -67900,11 +67955,11 @@ function detectPowerlineFont() {
67900
67955
  }
67901
67956
  }
67902
67957
  function PowerlineSetup({ settings, onUpdate, onBack }) {
67903
- const [screen, setScreen] = import_react45.useState("menu");
67904
- const [selected, setSelected] = import_react45.useState(0);
67905
- const [confirmEnable, setConfirmEnable] = import_react45.useState(false);
67958
+ const [screen, setScreen] = import_react51.useState("menu");
67959
+ const [selected, setSelected] = import_react51.useState(0);
67960
+ const [confirmEnable, setConfirmEnable] = import_react51.useState(false);
67906
67961
  const browserRuntime = process.env.CXSTATUSLINE_WEB === "1";
67907
- const fontFound = import_react45.useMemo(() => browserRuntime ? false : detectPowerlineFont(), [browserRuntime]);
67962
+ const fontFound = import_react51.useMemo(() => browserRuntime ? false : detectPowerlineFont(), [browserRuntime]);
67908
67963
  const powerline = settings.powerline;
67909
67964
  const manualSeparators = settings.lines.some((line3) => line3.some((item) => item.type === "separator"));
67910
67965
  use_input_default((input2, key) => {
@@ -67926,7 +67981,7 @@ function PowerlineSetup({ settings, onUpdate, onBack }) {
67926
67981
  }
67927
67982
  });
67928
67983
  if (screen === "separator" || screen === "startCap" || screen === "endCap") {
67929
- return /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(PowerlineSeparatorEditor, {
67984
+ return /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(PowerlineSeparatorEditor, {
67930
67985
  settings,
67931
67986
  mode: screen,
67932
67987
  onUpdate,
@@ -67934,23 +67989,23 @@ function PowerlineSetup({ settings, onUpdate, onBack }) {
67934
67989
  }, undefined, false, undefined, this);
67935
67990
  }
67936
67991
  if (screen === "themes")
67937
- return /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(PowerlineThemeSelector, {
67992
+ return /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(PowerlineThemeSelector, {
67938
67993
  settings,
67939
67994
  onUpdate,
67940
67995
  onBack: () => setScreen("menu")
67941
67996
  }, undefined, false, undefined, this);
67942
67997
  if (confirmEnable) {
67943
- return /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Box_default, {
67998
+ return /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Box_default, {
67944
67999
  flexDirection: "column",
67945
68000
  children: [
67946
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68001
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67947
68002
  color: "yellow",
67948
68003
  children: "Enabling Powerline removes manual separators from the status lines."
67949
68004
  }, undefined, false, undefined, this),
67950
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68005
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67951
68006
  children: "Continue?"
67952
68007
  }, undefined, false, undefined, this),
67953
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(ConfirmDialog, {
68008
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(ConfirmDialog, {
67954
68009
  inline: true,
67955
68010
  onConfirm: () => {
67956
68011
  onUpdate(buildEnabledPowerlineSettings(settings, true));
@@ -67961,53 +68016,53 @@ function PowerlineSetup({ settings, onUpdate, onBack }) {
67961
68016
  ]
67962
68017
  }, undefined, true, undefined, this);
67963
68018
  }
67964
- return /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Box_default, {
68019
+ return /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Box_default, {
67965
68020
  flexDirection: "column",
67966
68021
  children: [
67967
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68022
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67968
68023
  bold: true,
67969
68024
  children: "Powerline Setup"
67970
68025
  }, undefined, false, undefined, this),
67971
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68026
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67972
68027
  dimColor: true,
67973
68028
  children: browserRuntime ? "Font detection: unavailable in browser (the browser terminal decides glyph rendering)" : `Font detection: ${fontFound ? "compatible font found" : "no compatible font found"} (informational; terminal configuration controls glyph rendering)`
67974
68029
  }, undefined, false, undefined, this),
67975
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68030
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67976
68031
  children: [
67977
68032
  "Powerline Mode: ",
67978
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68033
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67979
68034
  color: powerline.enabled ? "green" : "red",
67980
68035
  children: powerline.enabled ? "Enabled" : "Disabled"
67981
68036
  }, undefined, false, undefined, this),
67982
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68037
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67983
68038
  dimColor: true,
67984
68039
  children: " — press (t) to toggle"
67985
68040
  }, undefined, false, undefined, this)
67986
68041
  ]
67987
68042
  }, undefined, true, undefined, this),
67988
- powerline.enabled && /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(jsx_dev_runtime24.Fragment, {
68043
+ powerline.enabled && /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(jsx_dev_runtime26.Fragment, {
67989
68044
  children: [
67990
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68045
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67991
68046
  children: [
67992
68047
  "Align Widgets: ",
67993
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68048
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67994
68049
  color: powerline.autoAlign ? "green" : "red",
67995
68050
  children: powerline.autoAlign ? "Enabled" : "Disabled"
67996
68051
  }, undefined, false, undefined, this),
67997
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68052
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67998
68053
  dimColor: true,
67999
68054
  children: " — press (a) to toggle"
68000
68055
  }, undefined, false, undefined, this)
68001
68056
  ]
68002
68057
  }, undefined, true, undefined, this),
68003
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68058
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
68004
68059
  children: [
68005
68060
  "Continue Theme: ",
68006
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68061
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
68007
68062
  color: powerline.continueThemeAcrossLines ? "green" : "red",
68008
68063
  children: powerline.continueThemeAcrossLines ? "Enabled" : "Disabled"
68009
68064
  }, undefined, false, undefined, this),
68010
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68065
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
68011
68066
  dimColor: true,
68012
68067
  children: " — press (c) to toggle"
68013
68068
  }, undefined, false, undefined, this)
@@ -68015,11 +68070,11 @@ function PowerlineSetup({ settings, onUpdate, onBack }) {
68015
68070
  }, undefined, true, undefined, this)
68016
68071
  ]
68017
68072
  }, undefined, true, undefined, this),
68018
- !powerline.enabled && /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68073
+ !powerline.enabled && /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
68019
68074
  dimColor: true,
68020
68075
  children: "Enable Powerline mode to configure separators, caps, and themes."
68021
68076
  }, undefined, false, undefined, this),
68022
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(List, {
68077
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(List, {
68023
68078
  marginTop: 1,
68024
68079
  items: buildPowerlineSetupMenuItems(powerline),
68025
68080
  initialSelection: selected,
@@ -68037,7 +68092,7 @@ function PowerlineSetup({ settings, onUpdate, onBack }) {
68037
68092
  }
68038
68093
 
68039
68094
  // src/tui/App.tsx
68040
- var jsx_dev_runtime25 = __toESM(require_jsx_dev_runtime(), 1);
68095
+ var jsx_dev_runtime27 = __toESM(require_jsx_dev_runtime(), 1);
68041
68096
  var readImportFileFromDisk = (file2) => readFile2(file2, "utf8");
68042
68097
  function cloneSettings(settings) {
68043
68098
  const clone3 = globalThis.structuredClone;
@@ -68052,26 +68107,26 @@ function App2({ initialSettings, settingsPath, readImportFile = readImportFileFr
68052
68107
  const { exit: nativeExit } = use_app_default();
68053
68108
  const exit = onExit ?? nativeExit;
68054
68109
  const { stdout } = use_stdout_default();
68055
- const [settings, setSettings] = import_react46.useState(() => initialSettings ? clampSettings(initialSettings) : null);
68056
- const [originalSettings, setOriginalSettings] = import_react46.useState(() => initialSettings ? clampSettings(initialSettings) : null);
68057
- const [screen, setScreen] = import_react46.useState("main");
68058
- const [selectedLine, setSelectedLine] = import_react46.useState(0);
68059
- const [colorLine, setColorLine] = import_react46.useState(null);
68060
- const [flash, setFlash] = import_react46.useState(null);
68061
- const [importError, setImportError] = import_react46.useState(null);
68062
- const [importPreview, setImportPreview] = import_react46.useState(null);
68063
- const [importApplying, setImportApplying] = import_react46.useState(false);
68064
- const [terminalWidth, setTerminalWidth] = import_react46.useState(() => stdout.columns || 80);
68065
- const importGeneration = import_react46.useRef(0);
68066
- const importApplyPending = import_react46.useRef(false);
68067
- import_react46.useEffect(() => {
68110
+ const [settings, setSettings] = import_react52.useState(() => initialSettings ? clampSettings(initialSettings) : null);
68111
+ const [originalSettings, setOriginalSettings] = import_react52.useState(() => initialSettings ? clampSettings(initialSettings) : null);
68112
+ const [screen, setScreen] = import_react52.useState("main");
68113
+ const [selectedLine, setSelectedLine] = import_react52.useState(0);
68114
+ const [colorLine, setColorLine] = import_react52.useState(null);
68115
+ const [flash, setFlash] = import_react52.useState(null);
68116
+ const [importError, setImportError] = import_react52.useState(null);
68117
+ const [importPreview, setImportPreview] = import_react52.useState(null);
68118
+ const [importApplying, setImportApplying] = import_react52.useState(false);
68119
+ const [terminalWidth, setTerminalWidth] = import_react52.useState(() => stdout.columns || 80);
68120
+ const importGeneration = import_react52.useRef(0);
68121
+ const importApplyPending = import_react52.useRef(false);
68122
+ import_react52.useEffect(() => {
68068
68123
  const updateWidth = () => setTerminalWidth(stdout.columns || 80);
68069
68124
  stdout.on("resize", updateWidth);
68070
68125
  return () => {
68071
68126
  stdout.off("resize", updateWidth);
68072
68127
  };
68073
68128
  }, [stdout]);
68074
- import_react46.useEffect(() => {
68129
+ import_react52.useEffect(() => {
68075
68130
  if (initialSettings)
68076
68131
  return;
68077
68132
  let active = true;
@@ -68096,10 +68151,10 @@ function App2({ initialSettings, settingsPath, readImportFile = readImportFileFr
68096
68151
  active = false;
68097
68152
  };
68098
68153
  }, [initialSettings, settingsPath]);
68099
- import_react46.useEffect(() => () => {
68154
+ import_react52.useEffect(() => () => {
68100
68155
  importGeneration.current += 1;
68101
68156
  }, []);
68102
- const hasChanges = import_react46.useMemo(() => Boolean(settings && originalSettings && JSON.stringify(settings) !== JSON.stringify(originalSettings)), [settings, originalSettings]);
68157
+ const hasChanges = import_react52.useMemo(() => Boolean(settings && originalSettings && JSON.stringify(settings) !== JSON.stringify(originalSettings)), [settings, originalSettings]);
68103
68158
  const replaceSettings = (next) => setSettings(clampSettings(next));
68104
68159
  const beginEdit = (nextScreen) => {
68105
68160
  if (!settings)
@@ -68241,45 +68296,45 @@ function App2({ initialSettings, settingsPath, readImportFile = readImportFileFr
68241
68296
  }
68242
68297
  };
68243
68298
  if (!settings) {
68244
- return /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Box_default, {
68245
- children: /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
68299
+ return /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(Box_default, {
68300
+ children: /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(Text, {
68246
68301
  children: "Loading configuration…"
68247
68302
  }, undefined, false, undefined, this)
68248
68303
  }, undefined, false, undefined, this);
68249
68304
  }
68250
- return /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Box_default, {
68305
+ return /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(Box_default, {
68251
68306
  flexDirection: "column",
68252
68307
  children: [
68253
- /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
68308
+ /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(Text, {
68254
68309
  bold: true,
68255
68310
  children: "cxstatusline Configuration"
68256
68311
  }, undefined, false, undefined, this),
68257
- flash && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
68312
+ flash && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(Text, {
68258
68313
  color: "yellow",
68259
68314
  children: flash
68260
68315
  }, undefined, false, undefined, this),
68261
- /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Box_default, {
68316
+ /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(Box_default, {
68262
68317
  marginTop: 1,
68263
68318
  flexDirection: "column",
68264
68319
  children: [
68265
- /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
68320
+ /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(Text, {
68266
68321
  dimColor: true,
68267
68322
  children: "> Preview"
68268
68323
  }, undefined, false, undefined, this),
68269
- /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(StatusLinePreview, {
68324
+ /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(StatusLinePreview, {
68270
68325
  settings,
68271
68326
  terminalWidth
68272
68327
  }, undefined, false, undefined, this)
68273
68328
  ]
68274
68329
  }, undefined, true, undefined, this),
68275
- /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Box_default, {
68330
+ /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(Box_default, {
68276
68331
  marginTop: 1,
68277
68332
  children: [
68278
- screen === "main" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(MainMenu, {
68333
+ screen === "main" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(MainMenu, {
68279
68334
  hasChanges,
68280
68335
  onSelect: (value) => handleMainMenu(value)
68281
68336
  }, undefined, false, undefined, this),
68282
- screen === "lines" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(LineSelector, {
68337
+ screen === "lines" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(LineSelector, {
68283
68338
  lines: settings.lines,
68284
68339
  onSelect: (line3) => {
68285
68340
  setSelectedLine(line3);
@@ -68290,59 +68345,59 @@ function App2({ initialSettings, settingsPath, readImportFile = readImportFileFr
68290
68345
  title: "Edit Lines",
68291
68346
  allowEditing: true
68292
68347
  }, undefined, false, undefined, this),
68293
- screen === "items" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(ItemsEditor, {
68348
+ screen === "items" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(ItemsEditor, {
68294
68349
  widgets: settings.lines[selectedLine] ?? [],
68295
68350
  onUpdate: (widgets) => updateLine(selectedLine, widgets),
68296
68351
  onBack: () => setScreen("lines"),
68297
68352
  lineNumber: selectedLine + 1,
68298
68353
  settings
68299
68354
  }, undefined, false, undefined, this),
68300
- screen === "colors" && colorLine === null && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(LineSelector, {
68355
+ screen === "colors" && colorLine === null && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(LineSelector, {
68301
68356
  lines: settings.lines,
68302
68357
  onSelect: setColorLine,
68303
68358
  onBack: () => finishEdit(),
68304
68359
  title: "Edit Colors"
68305
68360
  }, undefined, false, undefined, this),
68306
- screen === "colors" && colorLine !== null && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(ColorMenu, {
68361
+ screen === "colors" && colorLine !== null && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(ColorMenu, {
68307
68362
  widgets: settings.lines[colorLine] ?? [],
68308
68363
  lineIndex: colorLine,
68309
68364
  settings,
68310
68365
  onUpdate: (widgets) => updateLine(colorLine, widgets),
68311
68366
  onBack: () => setColorLine(null)
68312
68367
  }, undefined, false, undefined, this),
68313
- screen === "powerline" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(PowerlineSetup, {
68368
+ screen === "powerline" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(PowerlineSetup, {
68314
68369
  settings,
68315
68370
  onUpdate: replaceSettings,
68316
68371
  onBack: () => finishEdit()
68317
68372
  }, undefined, false, undefined, this),
68318
- screen === "overrides" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(GlobalOverridesMenu, {
68373
+ screen === "overrides" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(GlobalOverridesMenu, {
68319
68374
  settings,
68320
68375
  onUpdate: replaceSettings,
68321
68376
  onBack: () => finishEdit()
68322
68377
  }, undefined, false, undefined, this),
68323
- screen === "export" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(ExportConfigDialog, {
68378
+ screen === "export" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(ExportConfigDialog, {
68324
68379
  initialPath: `${settingsPath}.export.json`,
68325
68380
  onExport: exportSettings,
68326
68381
  onCancel: () => finishEdit()
68327
68382
  }, undefined, false, undefined, this),
68328
- screen === "import" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(ImportConfigDialog, {
68383
+ screen === "import" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(ImportConfigDialog, {
68329
68384
  error: importError,
68330
68385
  onFileChosen: importSettings,
68331
68386
  onCancel: () => finishEdit()
68332
68387
  }, undefined, false, undefined, this),
68333
- screen === "import-preview" && importPreview && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(ImportPreviewDialog, {
68388
+ screen === "import-preview" && importPreview && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(ImportPreviewDialog, {
68334
68389
  preview: importPreview,
68335
68390
  terminalWidth,
68336
68391
  busy: importApplying,
68337
68392
  onConfirm: () => void applyImport(),
68338
68393
  onCancel: () => finishEdit()
68339
68394
  }, undefined, false, undefined, this),
68340
- screen === "confirm-save" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(ConfirmDialog, {
68395
+ screen === "confirm-save" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(ConfirmDialog, {
68341
68396
  message: "Save the current configuration and exit?",
68342
68397
  onConfirm: () => void saveAndExit(),
68343
68398
  onCancel: () => setScreen("main")
68344
68399
  }, undefined, false, undefined, this),
68345
- screen === "confirm-discard" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(ConfirmDialog, {
68400
+ screen === "confirm-discard" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(ConfirmDialog, {
68346
68401
  message: hasChanges ? "Discard unsaved changes and exit?" : "Exit without saving?",
68347
68402
  onConfirm: () => {
68348
68403
  if (originalSettings)
@@ -68351,7 +68406,7 @@ function App2({ initialSettings, settingsPath, readImportFile = readImportFileFr
68351
68406
  },
68352
68407
  onCancel: () => setScreen("main")
68353
68408
  }, undefined, false, undefined, this),
68354
- screen === "confirm-invalid-replace" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(ConfirmDialog, {
68409
+ screen === "confirm-invalid-replace" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(ConfirmDialog, {
68355
68410
  message: "Existing settings could not be parsed and have not been changed. Use default settings in memory? Saving later will replace the file.",
68356
68411
  onConfirm: () => {
68357
68412
  const defaults2 = clampSettings(DEFAULT_SETTINGS);
@@ -68368,7 +68423,7 @@ function App2({ initialSettings, settingsPath, readImportFile = readImportFileFr
68368
68423
  }
68369
68424
  async function runTUI(settingsPath) {
68370
68425
  process.stdout.write("\x1B[2J\x1B[H");
68371
- const instance = render_default(/* @__PURE__ */ jsx_dev_runtime25.jsxDEV(App2, {
68426
+ const instance = render_default(/* @__PURE__ */ jsx_dev_runtime27.jsxDEV(App2, {
68372
68427
  settingsPath
68373
68428
  }, undefined, false, undefined, this));
68374
68429
  await instance.waitUntilExit();
@@ -68419,7 +68474,7 @@ var USAGE = `usage: cxstatusline [command]
68419
68474
  install the published Codex pair (--compile builds it from source)
68420
68475
  patch [--force] build and install the patched Codex from source
68421
68476
  patch --simulate-drift <v> record <v> as the installed version so the next session sees drift
68422
- update [--compile|--force] run upstream's own updater, then install the pair for it
68477
+ update [--compile|--force] install the latest supported patched Codex pair
68423
68478
  hook [install|uninstall] manage the SessionStart entry; bare 'hook' is what Codex runs
68424
68479
  doctor report toolchain, drift, hook and wrapper state
68425
68480
  policy [get|set <policy>] view or update policy (every, stable-minors, manual)
@@ -68501,8 +68556,15 @@ async function installCommand(argv, io2, deps) {
68501
68556
  }
68502
68557
  const ctx = contextFor(io2, deps);
68503
68558
  if (io2.isTTY === true && !yes && !codexVersion) {
68559
+ let manifest;
68504
68560
  try {
68505
- const manifest = loadManifest(ctx.patchesDir);
68561
+ manifest = loadManifest(ctx.patchesDir);
68562
+ } catch (e) {
68563
+ io2.stderr(`Cannot load supported Codex versions: ${e instanceof Error ? e.message : String(e)}
68564
+ `);
68565
+ return 1;
68566
+ }
68567
+ if (manifest) {
68506
68568
  const supported = supportedCodexVersions(manifest);
68507
68569
  if (supported.length > 0) {
68508
68570
  let prebuiltVersions;
@@ -68536,15 +68598,21 @@ async function installCommand(argv, io2, deps) {
68536
68598
  supportedVersions: supported,
68537
68599
  prebuiltVersions,
68538
68600
  defaultVersion,
68601
+ compile: compile3,
68539
68602
  isTTY: true,
68540
68603
  say: (l) => io2.stdout(`${l}
68541
68604
  `)
68542
68605
  });
68606
+ if (result2 === null) {
68607
+ io2.stdout(`Installation cancelled.
68608
+ `);
68609
+ return 0;
68610
+ }
68543
68611
  const selection = typeof result2 === "string" ? { version: result2, compile: false } : result2;
68544
68612
  codexVersion = selection.version;
68545
68613
  compile3 = compile3 || selection.compile;
68546
68614
  }
68547
- } catch {}
68615
+ }
68548
68616
  }
68549
68617
  return runInstall(ctx, { compile: compile3, codexVersion }, deps.transport);
68550
68618
  }
@@ -68559,7 +68627,7 @@ async function updateCommand(argv, io2, deps) {
68559
68627
  compile: flags.includes("--compile"),
68560
68628
  force: flags.includes("--force") || flags.includes("-y") || flags.includes("--yes"),
68561
68629
  isTTY: io2.isTTY,
68562
- ask: deps.ask,
68630
+ promptUpdate: deps.promptUpdate,
68563
68631
  fetchPrebuilts: deps.fetchPrebuilts
68564
68632
  }, deps.transport);
68565
68633
  }
@@ -68648,12 +68716,17 @@ async function main(argv, io2, deps = {}) {
68648
68716
  return 2;
68649
68717
  }
68650
68718
 
68719
+ // src/utils/interactive.ts
68720
+ function canPrompt(stdin, stdout) {
68721
+ return Boolean(stdin.isTTY && stdout.isTTY);
68722
+ }
68723
+
68651
68724
  // src/cli.ts
68652
68725
  var argv = process.argv.slice(2);
68653
68726
  var isHook = argv.length === 1 && argv[0] === "hook";
68654
68727
  main(argv, {
68655
68728
  env: process.env,
68656
- isTTY: Boolean(process.stdin.isTTY),
68729
+ isTTY: canPrompt(process.stdin, process.stdout),
68657
68730
  stdin: () => {
68658
68731
  try {
68659
68732
  return readFileSync15(0, "utf8");