cxstatusline 0.7.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.
@@ -47725,6 +47725,7 @@ var HIDE_KEYBIND = {
47725
47725
  };
47726
47726
  var NO_GIT_HIDEABLE_STATE = { key: "no-git", label: "when not in a git repo" };
47727
47727
  var ZERO_HIDEABLE_STATE = { key: "zero", label: "when value is zero" };
47728
+ var MERGE_TARGET_HIDDEN_HIDEABLE_STATE = { key: "merge-target-hidden", label: "when merge target is hidden" };
47728
47729
  function parseHideStates(value) {
47729
47730
  if (value === undefined) {
47730
47731
  return [];
@@ -47836,7 +47837,7 @@ class ClaudeSessionIdWidget {
47836
47837
  return "Shows the current Codex session ID";
47837
47838
  }
47838
47839
  getDisplayName() {
47839
- return "Claude Session ID";
47840
+ return "Codex Session ID";
47840
47841
  }
47841
47842
  getCategory() {
47842
47843
  return "Core";
@@ -48597,8 +48598,8 @@ class ContextBarWidget {
48597
48598
  if (total === null || used === null || total <= 0)
48598
48599
  return null;
48599
48600
  const percent = Math.max(0, Math.min(100, used / total * 100));
48600
- const usedText = formatTokens(used, tokenFormat);
48601
- const totalText = formatTokens(total, tokenFormat);
48601
+ const usedText = formatTokens(used, tokenFormat, 0);
48602
+ const totalText = formatTokens(total, tokenFormat, 0);
48602
48603
  const percentText = formatPercent(percent, percentFormat, 0);
48603
48604
  if (sliderMode(mode)) {
48604
48605
  const slider = makeSliderBar(percent);
@@ -53399,6 +53400,7 @@ class Ink {
53399
53400
  log;
53400
53401
  throttledLog;
53401
53402
  isScreenReaderEnabled;
53403
+ isInCi;
53402
53404
  isUnmounted;
53403
53405
  lastOutput;
53404
53406
  lastOutputHeight;
@@ -53411,6 +53413,7 @@ class Ink {
53411
53413
  constructor(options) {
53412
53414
  autoBind(this);
53413
53415
  this.options = options;
53416
+ this.isInCi = options.isCI ?? is_in_ci_default;
53414
53417
  this.rootNode = createNode("ink-root");
53415
53418
  this.rootNode.onComputeLayout = this.calculateLayout;
53416
53419
  this.isScreenReaderEnabled = options.isScreenReaderEnabled ?? process12.env["INK_SCREEN_READER"] === "true";
@@ -53441,7 +53444,7 @@ class Ink {
53441
53444
  if (options.patchConsole) {
53442
53445
  this.patchConsole();
53443
53446
  }
53444
- if (!is_in_ci_default) {
53447
+ if (!this.isInCi) {
53445
53448
  options.stdout.on("resize", this.resized);
53446
53449
  this.unsubscribeResize = () => {
53447
53450
  options.stdout.off("resize", this.resized);
@@ -53474,7 +53477,7 @@ class Ink {
53474
53477
  this.options.stdout.write(this.fullStaticOutput + output2);
53475
53478
  return;
53476
53479
  }
53477
- if (is_in_ci_default) {
53480
+ if (this.isInCi) {
53478
53481
  if (hasStaticOutput) {
53479
53482
  this.options.stdout.write(staticOutput);
53480
53483
  }
@@ -53485,7 +53488,7 @@ class Ink {
53485
53488
  if (hasStaticOutput) {
53486
53489
  this.fullStaticOutput += staticOutput;
53487
53490
  }
53488
- if (this.lastOutputHeight >= this.options.stdout.rows) {
53491
+ if (!this.options.preserveScrollback && this.lastOutputHeight >= this.options.stdout.rows) {
53489
53492
  this.options.stdout.write(exports_base.clearTerminal + this.fullStaticOutput + output2 + `
53490
53493
  `);
53491
53494
  this.lastOutput = output2;
@@ -53517,7 +53520,7 @@ class Ink {
53517
53520
  this.options.stdout.write(data + this.fullStaticOutput + this.lastOutput);
53518
53521
  return;
53519
53522
  }
53520
- if (is_in_ci_default) {
53523
+ if (this.isInCi) {
53521
53524
  this.options.stdout.write(data);
53522
53525
  return;
53523
53526
  }
@@ -53534,7 +53537,7 @@ class Ink {
53534
53537
  this.options.stdout.write(this.fullStaticOutput + this.lastOutput);
53535
53538
  return;
53536
53539
  }
53537
- if (is_in_ci_default) {
53540
+ if (this.isInCi) {
53538
53541
  this.options.stderr.write(data);
53539
53542
  return;
53540
53543
  }
@@ -53555,7 +53558,7 @@ class Ink {
53555
53558
  if (typeof this.unsubscribeResize === "function") {
53556
53559
  this.unsubscribeResize();
53557
53560
  }
53558
- if (is_in_ci_default) {
53561
+ if (this.isInCi) {
53559
53562
  this.options.stdout.write(this.lastOutput + `
53560
53563
  `);
53561
53564
  } else if (!this.options.debug) {
@@ -53579,7 +53582,7 @@ class Ink {
53579
53582
  return this.exitPromise;
53580
53583
  }
53581
53584
  clear() {
53582
- if (!is_in_ci_default && !this.options.debug) {
53585
+ if (!this.isInCi && !this.options.debug) {
53583
53586
  this.log.clear();
53584
53587
  }
53585
53588
  }
@@ -54502,6 +54505,9 @@ class CustomSymbolWidget {
54502
54505
  action: "edit-symbol"
54503
54506
  }];
54504
54507
  }
54508
+ getHideableStates() {
54509
+ return [MERGE_TARGET_HIDDEN_HIDEABLE_STATE];
54510
+ }
54505
54511
  renderEditor(props) {
54506
54512
  return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(CustomSymbolEditor, {
54507
54513
  ...props
@@ -54594,6 +54600,9 @@ class CustomTextWidget {
54594
54600
  action: "edit-text"
54595
54601
  }];
54596
54602
  }
54603
+ getHideableStates() {
54604
+ return [MERGE_TARGET_HIDDEN_HIDEABLE_STATE];
54605
+ }
54597
54606
  renderEditor(props) {
54598
54607
  return /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(CustomTextEditor, {
54599
54608
  ...props
@@ -55787,6 +55796,9 @@ class FiveHourUsageWidget {
55787
55796
  modifierText: getUsageDisplayModifierText(item, { showUsageDirection: true })
55788
55797
  };
55789
55798
  }
55799
+ getHideableStates() {
55800
+ return [USAGE_NO_DATA_HIDEABLE_STATE];
55801
+ }
55790
55802
  handleEditorAction(action, item) {
55791
55803
  if (action === "toggle-progress") {
55792
55804
  return cycleUsageDisplayMode(item, [], true, true);
@@ -55822,8 +55834,9 @@ class FiveHourUsageWidget {
55822
55834
  }
55823
55835
  const data = context.usageData ?? {};
55824
55836
  if (data.fiveHourUsage === undefined) {
55825
- if (data.error)
55826
- return getUsageErrorMessage(data.error);
55837
+ if (data.error) {
55838
+ return isHideStateEnabled(item, USAGE_NO_DATA_HIDEABLE_STATE) ? null : getUsageErrorMessage(data.error);
55839
+ }
55827
55840
  return null;
55828
55841
  }
55829
55842
  const percent = Math.max(0, Math.min(100, data.fiveHourUsage));
@@ -56772,6 +56785,7 @@ class SandboxStatusWidget {
56772
56785
  }
56773
56786
  }
56774
56787
  // src/widgets/SessionClock.ts
56788
+ var ZERO_HIDEABLE_STATE2 = { key: "zero", label: "when under 1 minute" };
56775
56789
  function formatDuration(ms) {
56776
56790
  const minutes = Math.floor(Math.max(0, ms) / 60000);
56777
56791
  if (minutes < 1)
@@ -56799,11 +56813,17 @@ class SessionClockWidget {
56799
56813
  getEditorDisplay(_item) {
56800
56814
  return { displayText: this.getDisplayName() };
56801
56815
  }
56816
+ getHideableStates() {
56817
+ return [ZERO_HIDEABLE_STATE2];
56818
+ }
56802
56819
  render(item, context, _settings) {
56803
56820
  const started = context.isPreview ? Date.parse("2026-09-02T09:45:00Z") : Date.parse(context.data.session?.started_at ?? "");
56804
56821
  if (!Number.isFinite(started))
56805
56822
  return null;
56806
- const value = formatDuration(context.now.getTime() - started);
56823
+ const elapsedMs = context.now.getTime() - started;
56824
+ if (elapsedMs < 60000 && isHideStateEnabled(item, ZERO_HIDEABLE_STATE2))
56825
+ return null;
56826
+ const value = formatDuration(elapsedMs);
56807
56827
  return item.rawValue ? value : "Session: " + value;
56808
56828
  }
56809
56829
  supportsRawValue() {
@@ -57051,12 +57071,19 @@ class TokensCachedWidget {
57051
57071
  getEditorDisplay(_item) {
57052
57072
  return { displayText: this.getDisplayName() };
57053
57073
  }
57074
+ getHideableStates() {
57075
+ return [ZERO_HIDEABLE_STATE];
57076
+ }
57054
57077
  render(item, context, settings) {
57055
57078
  const format = resolveNumberFormat("token", item, settings);
57056
57079
  if (context.isPreview)
57057
57080
  return formatRawOrLabeledValue(item, "Cached: ", formatTokens(12000, format, 0));
57058
57081
  const value = context.data.usage?.cached_input_tokens ?? null;
57059
- return value === null ? null : formatRawOrLabeledValue(item, "Cached: ", formatTokens(value, format));
57082
+ if (value === null)
57083
+ return null;
57084
+ if (value === 0 && isHideStateEnabled(item, ZERO_HIDEABLE_STATE))
57085
+ return null;
57086
+ return formatRawOrLabeledValue(item, "Cached: ", formatTokens(value, format));
57060
57087
  }
57061
57088
  supportsRawValue() {
57062
57089
  return true;
@@ -57085,12 +57112,19 @@ class TokensInputWidget {
57085
57112
  getEditorDisplay(_item) {
57086
57113
  return { displayText: this.getDisplayName() };
57087
57114
  }
57115
+ getHideableStates() {
57116
+ return [ZERO_HIDEABLE_STATE];
57117
+ }
57088
57118
  render(item, context, settings) {
57089
57119
  const format = resolveNumberFormat("token", item, settings);
57090
57120
  if (context.isPreview)
57091
57121
  return formatRawOrLabeledValue(item, "In: ", formatTokens(15200, format));
57092
57122
  const value = context.data.usage?.input_tokens ?? null;
57093
- return value === null ? null : formatRawOrLabeledValue(item, "In: ", formatTokens(value, format));
57123
+ if (value === null)
57124
+ return null;
57125
+ if (value === 0 && isHideStateEnabled(item, ZERO_HIDEABLE_STATE))
57126
+ return null;
57127
+ return formatRawOrLabeledValue(item, "In: ", formatTokens(value, format));
57094
57128
  }
57095
57129
  supportsRawValue() {
57096
57130
  return true;
@@ -57119,12 +57153,19 @@ class TokensOutputWidget {
57119
57153
  getEditorDisplay(_item) {
57120
57154
  return { displayText: this.getDisplayName() };
57121
57155
  }
57156
+ getHideableStates() {
57157
+ return [ZERO_HIDEABLE_STATE];
57158
+ }
57122
57159
  render(item, context, settings) {
57123
57160
  const format = resolveNumberFormat("token", item, settings);
57124
57161
  if (context.isPreview)
57125
57162
  return formatRawOrLabeledValue(item, "Out: ", formatTokens(3400, format));
57126
57163
  const value = context.data.usage?.output_tokens ?? null;
57127
- return value === null ? null : formatRawOrLabeledValue(item, "Out: ", formatTokens(value, format));
57164
+ if (value === null)
57165
+ return null;
57166
+ if (value === 0 && isHideStateEnabled(item, ZERO_HIDEABLE_STATE))
57167
+ return null;
57168
+ return formatRawOrLabeledValue(item, "Out: ", formatTokens(value, format));
57128
57169
  }
57129
57170
  supportsRawValue() {
57130
57171
  return true;
@@ -57153,12 +57194,19 @@ class TokensTotalWidget {
57153
57194
  getEditorDisplay(_item) {
57154
57195
  return { displayText: this.getDisplayName() };
57155
57196
  }
57197
+ getHideableStates() {
57198
+ return [ZERO_HIDEABLE_STATE];
57199
+ }
57156
57200
  render(item, context, settings) {
57157
57201
  const format = resolveNumberFormat("token", item, settings);
57158
57202
  if (context.isPreview)
57159
57203
  return formatRawOrLabeledValue(item, "Total: ", formatTokens(30600, format));
57160
57204
  const value = context.data.usage && context.data.usage.input_tokens !== undefined && context.data.usage.output_tokens !== undefined ? context.data.usage.input_tokens + context.data.usage.output_tokens : null;
57161
- return value === null ? null : formatRawOrLabeledValue(item, "Total: ", formatTokens(value, format));
57205
+ if (value === null)
57206
+ return null;
57207
+ if (value === 0 && isHideStateEnabled(item, ZERO_HIDEABLE_STATE))
57208
+ return null;
57209
+ return formatRawOrLabeledValue(item, "Total: ", formatTokens(value, format));
57162
57210
  }
57163
57211
  supportsRawValue() {
57164
57212
  return true;
@@ -57454,6 +57502,9 @@ class WeeklyUsageWidget {
57454
57502
  modifierText: getUsageDisplayModifierText(item, { showUsageDirection: true })
57455
57503
  };
57456
57504
  }
57505
+ getHideableStates() {
57506
+ return [USAGE_NO_DATA_HIDEABLE_STATE];
57507
+ }
57457
57508
  handleEditorAction(action, item) {
57458
57509
  if (action === "toggle-progress") {
57459
57510
  return cycleUsageDisplayMode(item, [], true, true);
@@ -57489,8 +57540,9 @@ class WeeklyUsageWidget {
57489
57540
  }
57490
57541
  const data = context.usageData ?? {};
57491
57542
  if (data.weeklyUsage === undefined) {
57492
- if (data.error)
57493
- return getUsageErrorMessage(data.error);
57543
+ if (data.error) {
57544
+ return isHideStateEnabled(item, USAGE_NO_DATA_HIDEABLE_STATE) ? null : getUsageErrorMessage(data.error);
57545
+ }
57494
57546
  return null;
57495
57547
  }
57496
57548
  const percent = Math.max(0, Math.min(100, data.weeklyUsage));
@@ -57568,6 +57620,7 @@ var WIDGET_MANIFEST = [
57568
57620
  { type: "session-clock", create: () => new SessionClockWidget },
57569
57621
  { type: "session-name", create: () => new SessionNameWidget },
57570
57622
  { type: "claude-session-id", create: () => new ClaudeSessionIdWidget },
57623
+ { type: "codex-session-id", create: () => new ClaudeSessionIdWidget },
57571
57624
  { type: "version", create: () => new VersionWidget },
57572
57625
  { type: "current-working-dir", create: () => new CurrentWorkingDirWidget },
57573
57626
  { type: "sandbox-status", create: () => new SandboxStatusWidget },
@@ -58190,6 +58243,46 @@ function countPowerlineStartCapSlots(widgets, preRenderedWidgets) {
58190
58243
  }
58191
58244
  return renderedSegmentCount;
58192
58245
  }
58246
+ var DECORATIVE_WIDGET_TYPES = new Set(["custom-text", "custom-symbol"]);
58247
+ function isSeparatorType(type) {
58248
+ return type === "separator" || type === "flex-separator";
58249
+ }
58250
+ function applyMergeTargetHiding(preRenderedLine) {
58251
+ let chainStart = 0;
58252
+ for (let i = 0;i <= preRenderedLine.length; i++) {
58253
+ const element = preRenderedLine[i];
58254
+ if (element && !isSeparatorType(element.widget.type)) {
58255
+ continue;
58256
+ }
58257
+ applyMergeTargetHidingToSegment(preRenderedLine.slice(chainStart, i));
58258
+ chainStart = i + 1;
58259
+ }
58260
+ }
58261
+ function applyMergeTargetHidingToSegment(segment) {
58262
+ let chainStart = 0;
58263
+ for (let i = 0;i < segment.length; i++) {
58264
+ const linksToNext = Boolean(segment[i]?.widget.merge) && i < segment.length - 1;
58265
+ if (linksToNext) {
58266
+ continue;
58267
+ }
58268
+ const chain = segment.slice(chainStart, i + 1);
58269
+ chainStart = i + 1;
58270
+ if (chain.length < 2) {
58271
+ continue;
58272
+ }
58273
+ for (let position = 0;position < chain.length; position++) {
58274
+ const element = chain[position];
58275
+ if (!element || !DECORATIVE_WIDGET_TYPES.has(element.widget.type) || !isHideStateEnabled(element.widget, MERGE_TARGET_HIDDEN_HIDEABLE_STATE)) {
58276
+ continue;
58277
+ }
58278
+ const target = chain.slice(position + 1).find((candidate) => !DECORATIVE_WIDGET_TYPES.has(candidate.widget.type)) ?? chain.slice(0, position).reverse().find((candidate) => !DECORATIVE_WIDGET_TYPES.has(candidate.widget.type));
58279
+ if (target?.content === "") {
58280
+ element.content = "";
58281
+ element.plainLength = 0;
58282
+ }
58283
+ }
58284
+ }
58285
+ }
58193
58286
  function preRenderAllWidgets(allLinesWidgets, settings, context) {
58194
58287
  const preRenderedLines = [];
58195
58288
  for (const lineWidgets of allLinesWidgets) {
@@ -58227,6 +58320,7 @@ function preRenderAllWidgets(allLinesWidgets, settings, context) {
58227
58320
  styled
58228
58321
  });
58229
58322
  }
58323
+ applyMergeTargetHiding(preRenderedLine);
58230
58324
  preRenderedLines.push(preRenderedLine);
58231
58325
  }
58232
58326
  return preRenderedLines;
@@ -58589,6 +58683,7 @@ var CANONICAL_WIDGET_TYPES = [
58589
58683
  "session-clock",
58590
58684
  "session-name",
58591
58685
  "claude-session-id",
58686
+ "codex-session-id",
58592
58687
  "version",
58593
58688
  "current-working-dir",
58594
58689
  "sandbox-status",
@@ -58912,14 +59007,14 @@ function runRefreshCommand(cacheKey2, deps) {
58912
59007
  return 0;
58913
59008
  }
58914
59009
  // src/version-info.ts
58915
- var VERSION = "0.7.0";
58916
- var SOURCE_COMMIT = /^[0-9a-f]{40}$/.test("e1daa573762212753a6a35fec0e3cc621cadb614") ? "e1daa573762212753a6a35fec0e3cc621cadb614" : null;
59010
+ var VERSION = "0.9.0";
59011
+ var SOURCE_COMMIT = /^[0-9a-f]{40}$/.test("6a7b82efae2605ec4e4346c7d482b7d5b7734347") ? "6a7b82efae2605ec4e4346c7d482b7d5b7734347" : null;
58917
59012
  var SOURCE_DIRTY = false;
58918
59013
 
58919
59014
  // src/context.ts
58920
59015
  import { existsSync as existsSync3, realpathSync } from "node:fs";
58921
59016
  import { spawnSync as spawnSync4 } from "node:child_process";
58922
- import { dirname as dirname5, join as join8 } from "node:path";
59017
+ import { fileURLToPath } from "node:url";
58923
59018
 
58924
59019
  // src/patch/preflight.ts
58925
59020
  import { accessSync, constants as constants2, existsSync as existsSync2, statfsSync } from "node:fs";
@@ -59046,7 +59141,7 @@ function realContext(env3, io) {
59046
59141
  which: deps.which,
59047
59142
  freeBytes: deps.freeBytes,
59048
59143
  cxBin: own2,
59049
- patchesDir: join8(dirname5(realpathSync(own2)), "..", "patches"),
59144
+ patchesDir: fileURLToPath(new URL("../patches", import.meta.url)),
59050
59145
  now: () => new Date,
59051
59146
  log: io.log,
59052
59147
  say: io.say
@@ -59055,11 +59150,11 @@ function realContext(env3, io) {
59055
59150
 
59056
59151
  // src/patch/run.ts
59057
59152
  import { appendFileSync, mkdirSync as mkdirSync8 } from "node:fs";
59058
- import { join as join19 } from "node:path";
59153
+ import { join as join18 } from "node:path";
59059
59154
 
59060
59155
  // src/lock.ts
59061
59156
  import { closeSync, existsSync as existsSync4, mkdirSync as mkdirSync3, openSync, readFileSync as readFileSync4, unlinkSync as unlinkSync3, writeSync } from "node:fs";
59062
- import { dirname as dirname6 } from "node:path";
59157
+ import { dirname as dirname5 } from "node:path";
59063
59158
  function pidAlive(pid) {
59064
59159
  try {
59065
59160
  process.kill(pid, 0);
@@ -59079,7 +59174,7 @@ function lockHolder(file2) {
59079
59174
  }
59080
59175
  }
59081
59176
  function acquireLock(file2, isAlive = pidAlive) {
59082
- mkdirSync3(dirname6(file2), { recursive: true });
59177
+ mkdirSync3(dirname5(file2), { recursive: true });
59083
59178
  for (let attempt2 = 0;attempt2 < 2; attempt2++) {
59084
59179
  try {
59085
59180
  const fd = openSync(file2, "wx");
@@ -59150,7 +59245,7 @@ function needsRepatch(upstream, patched, policy) {
59150
59245
  if (policy === "manual")
59151
59246
  return false;
59152
59247
  if (policy === "every")
59153
- return patched === null || compareSemver(upstream, patched) !== 0;
59248
+ return patched === null || compareSemver(upstream, patched) > 0;
59154
59249
  if (upstream.pre !== null)
59155
59250
  return false;
59156
59251
  if (patched === null)
@@ -59165,12 +59260,12 @@ function behindWithinMinor(upstream, patched) {
59165
59260
  // src/distribution/prebuilt.ts
59166
59261
  import { createHash as createHash4 } from "node:crypto";
59167
59262
  import { chmodSync as chmodSync2, copyFileSync as copyFileSync2, mkdirSync as mkdirSync5, mkdtempSync, readFileSync as readFileSync6, renameSync as renameSync4, rmSync as rmSync2 } from "node:fs";
59168
- import { join as join12 } from "node:path";
59263
+ import { join as join11 } from "node:path";
59169
59264
 
59170
59265
  // src/patch/generation.ts
59171
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";
59172
59267
  import { createHash as createHash2, randomBytes as randomBytes2 } from "node:crypto";
59173
- 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";
59174
59269
  var INSTALLATION_FILE = "installation.json";
59175
59270
  var SAFE_SEGMENT = /^[A-Za-z0-9][A-Za-z0-9._+-]*$/;
59176
59271
  function digestOf(file2) {
@@ -59189,7 +59284,7 @@ function nearestExisting2(p) {
59189
59284
  statSync(cur);
59190
59285
  return cur;
59191
59286
  } catch {
59192
- const parent = dirname7(cur);
59287
+ const parent = dirname6(cur);
59193
59288
  if (parent === cur)
59194
59289
  return cur;
59195
59290
  cur = parent;
@@ -59208,7 +59303,7 @@ function validateStaging(pair) {
59208
59303
  throw new Error(`prepared pair has an unusable codexVersion "${pair.codexVersion}"`);
59209
59304
  }
59210
59305
  for (const name of GENERATION_EXECUTABLES) {
59211
- const file2 = join9(pair.directory, name);
59306
+ const file2 = join8(pair.directory, name);
59212
59307
  if (!existsSync5(file2))
59213
59308
  throw new Error(`staged pair is missing ${name}`);
59214
59309
  const want = pair.provenance.executables[name];
@@ -59219,7 +59314,7 @@ function validateStaging(pair) {
59219
59314
  }
59220
59315
  if (pair.provenance.source === "prebuilt") {
59221
59316
  for (const name of GENERATION_LEGAL_FILES) {
59222
- if (!existsSync5(join9(pair.directory, name)))
59317
+ if (!existsSync5(join8(pair.directory, name)))
59223
59318
  throw new Error(`prebuilt pair is missing ${name}`);
59224
59319
  }
59225
59320
  }
@@ -59229,8 +59324,8 @@ function installationRecord(pair) {
59229
59324
  return record2;
59230
59325
  }
59231
59326
  function copyInto(from, into, name, mode, expected) {
59232
- const target = join9(into, name);
59233
- copyFileSync(join9(from, name), target);
59327
+ const target = join8(into, name);
59328
+ copyFileSync(join8(from, name), target);
59234
59329
  chmodSync(target, mode);
59235
59330
  if (!expected)
59236
59331
  return;
@@ -59240,7 +59335,7 @@ function copyInto(from, into, name, mode, expected) {
59240
59335
  }
59241
59336
  }
59242
59337
  function commitJson(file2, value, rename2) {
59243
- 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`);
59244
59339
  try {
59245
59340
  writeFileSync2(tmp, `${JSON.stringify(value, null, 2)}
59246
59341
  `);
@@ -59253,7 +59348,7 @@ function commitJson(file2, value, rename2) {
59253
59348
  function freshDirectory(pair, paths) {
59254
59349
  mkdirSync4(paths.generationsDir, { recursive: true });
59255
59350
  for (;; ) {
59256
- 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")}`);
59257
59352
  if (existsSync5(dir))
59258
59353
  continue;
59259
59354
  mkdirSync4(dir);
@@ -59267,10 +59362,10 @@ function createGeneration(pair, paths, rename2 = renameSync2) {
59267
59362
  for (const name of GENERATION_EXECUTABLES)
59268
59363
  copyInto(pair.directory, dir, name, 493, pair.provenance.executables[name]);
59269
59364
  for (const name of GENERATION_LEGAL_FILES) {
59270
- if (existsSync5(join9(pair.directory, name)))
59365
+ if (existsSync5(join8(pair.directory, name)))
59271
59366
  copyInto(pair.directory, dir, name, 420);
59272
59367
  }
59273
- commitJson(join9(dir, INSTALLATION_FILE), installationRecord(pair), rename2);
59368
+ commitJson(join8(dir, INSTALLATION_FILE), installationRecord(pair), rename2);
59274
59369
  } catch (e) {
59275
59370
  rmSync(dir, { recursive: true, force: true });
59276
59371
  throw e;
@@ -59278,11 +59373,11 @@ function createGeneration(pair, paths, rename2 = renameSync2) {
59278
59373
  return dir;
59279
59374
  }
59280
59375
  function isGenerationDir(dir) {
59281
- return existsSync5(join9(dir, INSTALLATION_FILE)) && existsSync5(join9(dir, "codex"));
59376
+ return existsSync5(join8(dir, INSTALLATION_FILE)) && existsSync5(join8(dir, "codex"));
59282
59377
  }
59283
59378
  function listGenerations(paths) {
59284
59379
  try {
59285
- return readdirSync2(paths.generationsDir).map((name) => join9(paths.generationsDir, name)).sort();
59380
+ return readdirSync2(paths.generationsDir).map((name) => join8(paths.generationsDir, name)).sort();
59286
59381
  } catch {
59287
59382
  return [];
59288
59383
  }
@@ -59315,7 +59410,7 @@ function activeGeneration(paths) {
59315
59410
  const target = readPointer(paths);
59316
59411
  if (target === null)
59317
59412
  return null;
59318
- const abs = isAbsolute(target) ? target : resolve2(dirname7(paths.currentGeneration), target);
59413
+ const abs = isAbsolute(target) ? target : resolve2(dirname6(paths.currentGeneration), target);
59319
59414
  if (!insideGenerationsRoot(paths, abs))
59320
59415
  return null;
59321
59416
  try {
@@ -59340,6 +59435,7 @@ var RecordSchema = exports_external.object({
59340
59435
  source: exports_external.enum(["prebuilt", "compiled"]),
59341
59436
  cxVersion: exports_external.string(),
59342
59437
  platform: exports_external.string(),
59438
+ patchVersion: exports_external.number().int().positive().max(Number.MAX_SAFE_INTEGER).optional(),
59343
59439
  patchSha256: exports_external.string().regex(HEX64, "patchSha256 must be 64 lowercase hex chars"),
59344
59440
  upstreamCommit: exports_external.string().regex(HEX40, "upstreamCommit must be 40 lowercase hex chars"),
59345
59441
  sourceCommit: exports_external.string().regex(HEX40, "sourceCommit must be 40 lowercase hex chars").nullable(),
@@ -59366,6 +59462,8 @@ function checkedRecord(v) {
59366
59462
  codexVersion: parsed.data.codexVersion,
59367
59463
  platform: provenance.platform
59368
59464
  });
59465
+ if (provenance.patchVersion !== manifest.patchVersion)
59466
+ return null;
59369
59467
  const release = { ...provenance.release, manifest };
59370
59468
  return { ...parsed.data, provenance: { ...provenance, release } };
59371
59469
  } catch {
@@ -59377,7 +59475,7 @@ function readInstallation(paths) {
59377
59475
  if (dir === null)
59378
59476
  return null;
59379
59477
  try {
59380
- const raw = JSON.parse(readFileSync5(join9(dir, INSTALLATION_FILE), "utf8"));
59478
+ const raw = JSON.parse(readFileSync5(join8(dir, INSTALLATION_FILE), "utf8"));
59381
59479
  return checkedRecord(raw);
59382
59480
  } catch {
59383
59481
  return null;
@@ -59386,7 +59484,7 @@ function readInstallation(paths) {
59386
59484
 
59387
59485
  // src/distribution/archive.ts
59388
59486
  import { createReadStream, createWriteStream } from "node:fs";
59389
- import { join as join10 } from "node:path";
59487
+ import { join as join9 } from "node:path";
59390
59488
  import { createGunzip } from "node:zlib";
59391
59489
 
59392
59490
  // node_modules/tar/dist/esm/index.min.js
@@ -62661,7 +62759,7 @@ function rejectionReason(entry, seen, budget) {
62661
62759
  function writeEntry(entry, staging) {
62662
62760
  const name = entry.path;
62663
62761
  const mode = isExecutable(name) ? EXECUTABLE_MODE : LEGAL_MODE;
62664
- const sink = createWriteStream(join10(staging, name), { mode, flags: "wx" });
62762
+ const sink = createWriteStream(join9(staging, name), { mode, flags: "wx" });
62665
62763
  const done = new Promise((resolve3, reject2) => {
62666
62764
  sink.on("error", reject2);
62667
62765
  entry.on("error", reject2);
@@ -62747,7 +62845,7 @@ async function extractArchive(archivePath, staging) {
62747
62845
  import { createHash as createHash3 } from "node:crypto";
62748
62846
  import { createReadStream as createReadStream2, existsSync as existsSync6, renameSync as renameSync3 } from "node:fs";
62749
62847
  import { open as open2 } from "node:fs/promises";
62750
- import { dirname as dirname8, join as join11 } from "node:path";
62848
+ import { dirname as dirname7, join as join10 } from "node:path";
62751
62849
  var PUBLIC_BASE = "https://github.com/adrijshikhar/cxstatusline/releases/download";
62752
62850
  var REPO = "adrijshikhar/cxstatusline";
62753
62851
  var MAX_REDIRECTS = 5;
@@ -62993,7 +63091,7 @@ async function ghDownload(ctx, tag, asset, dest, maxBytes) {
62993
63091
  if (ctx.which("gh") === null) {
62994
63092
  throw new GhMissingError(`${asset} is not public for release ${tag} and GitHub CLI (gh) is not installed`);
62995
63093
  }
62996
- const targetDir = dirname8(dest);
63094
+ const targetDir = dirname7(dest);
62997
63095
  const result2 = ctx.run("gh", ["release", "download", tag, "--repo", REPO, "--pattern", asset, "--dir", targetDir], { timeoutMs: GH_TIMEOUT_MS });
62998
63096
  if (result2.status !== 0) {
62999
63097
  const detail = sanitize(result2.stderr || result2.stdout);
@@ -63002,7 +63100,7 @@ async function ghDownload(ctx, tag, asset, dest, maxBytes) {
63002
63100
  }
63003
63101
  throw new ReleaseUnavailableError(`release ${tag} not found or access denied: ${detail}`);
63004
63102
  }
63005
- const downloadedFile = join11(targetDir, asset);
63103
+ const downloadedFile = join10(targetDir, asset);
63006
63104
  if (!existsSync6(downloadedFile) && !existsSync6(dest)) {
63007
63105
  throw new ReleaseUnavailableError(`release ${tag} not found or access denied: gh downloaded no ${asset}`);
63008
63106
  }
@@ -63031,7 +63129,7 @@ function sameDigest(a, b2) {
63031
63129
  }
63032
63130
  function privateTemp(ctx, prefix) {
63033
63131
  mkdirSync5(ctx.paths.libexecDir, { recursive: true });
63034
- const dir = mkdtempSync(join12(ctx.paths.libexecDir, prefix));
63132
+ const dir = mkdtempSync(join11(ctx.paths.libexecDir, prefix));
63035
63133
  chmodSync2(dir, 448);
63036
63134
  return dir;
63037
63135
  }
@@ -63049,7 +63147,7 @@ function unchangedPair(ctx, manifest, artifact, tag) {
63049
63147
  if (!release || release.tag !== tag || release.archiveSha256 !== artifact.sha256)
63050
63148
  return null;
63051
63149
  const installed = release.manifest;
63052
- 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;
63053
63151
  if (!identical)
63054
63152
  return null;
63055
63153
  const directory = activeGeneration(ctx.paths);
@@ -63057,7 +63155,7 @@ function unchangedPair(ctx, manifest, artifact, tag) {
63057
63155
  return null;
63058
63156
  for (const name of ARTIFACT_FILES) {
63059
63157
  try {
63060
- if (!sameDigest(digestOf2(join12(directory, name)), artifact.files[name]))
63158
+ if (!sameDigest(digestOf2(join11(directory, name)), artifact.files[name]))
63061
63159
  return null;
63062
63160
  } catch {
63063
63161
  return null;
@@ -63068,7 +63166,7 @@ function unchangedPair(ctx, manifest, artifact, tag) {
63068
63166
  function verifyStaged(staging, artifact) {
63069
63167
  const digests = {};
63070
63168
  for (const name of ARTIFACT_FILES) {
63071
- const got = digestOf2(join12(staging, name));
63169
+ const got = digestOf2(join11(staging, name));
63072
63170
  if (!sameDigest(got, artifact.files[name])) {
63073
63171
  throw new Error(`staged ${name} does not match the release manifest sha256`);
63074
63172
  }
@@ -63080,7 +63178,7 @@ function verifyStaged(staging, artifact) {
63080
63178
  };
63081
63179
  }
63082
63180
  function probeVersion(ctx, staging, codexVersion) {
63083
- 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 });
63084
63182
  const reported = sanitize((probe.stdout || probe.stderr).slice(0, 512));
63085
63183
  if (probe.status !== 0 || reported !== `codex-cli ${codexVersion}`) {
63086
63184
  throw new Error(`staged codex reported version "${reported}" instead of "codex-cli ${codexVersion}"`);
@@ -63096,6 +63194,7 @@ function stagedPair(ctx, staging, manifest, artifact, tag) {
63096
63194
  source: "prebuilt",
63097
63195
  cxVersion: manifest.cxVersion ?? VERSION,
63098
63196
  platform: artifact.platform,
63197
+ patchVersion: manifest.patchVersion,
63099
63198
  patchSha256: manifest.patchSha256,
63100
63199
  upstreamCommit: manifest.upstreamCommit,
63101
63200
  sourceCommit: manifest.sourceCommit,
@@ -63121,8 +63220,8 @@ function moveFile(src, dst) {
63121
63220
  async function stageArchive(ctx, download, manifest, artifact, tag, opts) {
63122
63221
  const cacheDir = ctx.paths.downloadCacheDir;
63123
63222
  mkdirSync5(cacheDir, { recursive: true });
63124
- const partFile = join12(cacheDir, `${tag}-${artifact.filename}.part`);
63125
- const archive = join12(download, artifact.filename);
63223
+ const partFile = join11(cacheDir, `${tag}-${artifact.filename}.part`);
63224
+ const archive = join11(download, artifact.filename);
63126
63225
  opts.onStatus?.("download", `Downloading prebuilt archive (${artifact.filename})...`);
63127
63226
  const got = await downloadAsset(ctx, tag, artifact.filename, partFile, ARCHIVE_MAX_BYTES, opts);
63128
63227
  if (got.sha256 !== artifact.sha256 || got.size !== artifact.size) {
@@ -63148,7 +63247,7 @@ async function preparePrebuilt(ctx, expected, opts = {}) {
63148
63247
  opts.onStatus?.("manifest", `Checking release ${tag} for ${expected.platform}...`);
63149
63248
  const download = privateTemp(ctx, "download-");
63150
63249
  try {
63151
- const manifestFile = join12(download, MANIFEST_ASSET);
63250
+ const manifestFile = join11(download, MANIFEST_ASSET);
63152
63251
  await downloadAsset(ctx, tag, MANIFEST_ASSET, manifestFile, MANIFEST_MAX_BYTES, opts);
63153
63252
  const manifest = validateManifest(JSON.parse(readFileSync6(manifestFile, "utf8")), expected);
63154
63253
  const artifact = artifactFor(manifest, expected);
@@ -63161,6 +63260,53 @@ async function preparePrebuilt(ctx, expected, opts = {}) {
63161
63260
  rmSync2(download, { recursive: true, force: true });
63162
63261
  }
63163
63262
  }
63263
+ async function fetchPublishedPrebuiltVersions(fetchFn, repo = "adrijshikhar/cxstatusline") {
63264
+ const fetcher = fetchFn ?? globalThis.fetch;
63265
+ try {
63266
+ const headers = {
63267
+ accept: "application/vnd.github+json",
63268
+ "user-agent": "cxstatusline"
63269
+ };
63270
+ if (process.env.GITHUB_TOKEN) {
63271
+ headers.authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
63272
+ }
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
+ }
63288
+ const versions2 = new Set;
63289
+ for (const item of data) {
63290
+ if (typeof item === "object" && item !== null) {
63291
+ const tag = item.tag_name;
63292
+ const draft = item.draft;
63293
+ if (typeof tag === "string" && !draft && tag.startsWith("codex-v")) {
63294
+ const v2 = tag.slice("codex-v".length);
63295
+ if (parseSemver(v2)) {
63296
+ versions2.add(v2);
63297
+ }
63298
+ }
63299
+ }
63300
+ }
63301
+ return Array.from(versions2).sort((a, b2) => {
63302
+ const semA = parseSemver(a);
63303
+ const semB = parseSemver(b2);
63304
+ return compareSemver(semB, semA);
63305
+ });
63306
+ } catch {
63307
+ return [];
63308
+ }
63309
+ }
63164
63310
 
63165
63311
  // src/distribution.ts
63166
63312
  var PLATFORMS = [
@@ -63211,7 +63357,8 @@ var ArtifactSchema = exports_external.object({
63211
63357
  files: FilesSchema
63212
63358
  }).strict();
63213
63359
  var ManifestShapeSchema = exports_external.object({
63214
- 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(),
63215
63362
  cxVersion: exports_external.string().optional(),
63216
63363
  codexVersion: exports_external.string(),
63217
63364
  upstreamTag: exports_external.string(),
@@ -63241,6 +63388,10 @@ function checkArtifacts(m2, expected) {
63241
63388
  return null;
63242
63389
  }
63243
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";
63244
63395
  if (m2.cxVersion !== undefined && !isStableVersion(m2.cxVersion)) {
63245
63396
  return "cxVersion is not a valid semver";
63246
63397
  }
@@ -63249,7 +63400,9 @@ function checkBusinessRules(m2, expected) {
63249
63400
  }
63250
63401
  if (m2.upstreamTag !== `rust-v${m2.codexVersion}`)
63251
63402
  return "upstreamTag does not match codexVersion";
63252
- 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`)
63253
63406
  return "patchFile does not match codexVersion";
63254
63407
  if (Number.isNaN(Date.parse(m2.createdAt)))
63255
63408
  return "createdAt is not a valid timestamp";
@@ -63277,82 +63430,6 @@ function validateManifest(raw, expected) {
63277
63430
  return structural.data;
63278
63431
  }
63279
63432
 
63280
- // src/codex/upstream.ts
63281
- import { accessSync as accessSync2, constants as constants3, lstatSync as lstatSync3, readlinkSync as readlinkSync2, realpathSync as realpathSync3, statSync as statSync2 } from "node:fs";
63282
- import { dirname as dirname9, isAbsolute as isAbsolute2, join as join13, resolve as resolve3 } from "node:path";
63283
- function isExecutable2(p2) {
63284
- try {
63285
- accessSync2(p2, constants3.X_OK);
63286
- return statSync2(p2).isFile();
63287
- } catch {
63288
- return false;
63289
- }
63290
- }
63291
- function isManaged(p2, paths, isOurWrapper) {
63292
- if (resolve3(p2) === resolve3(paths.patchedBin) || isOurWrapper(p2))
63293
- return true;
63294
- try {
63295
- return realpathSync3(p2) === realpathSync3(paths.patchedBin);
63296
- } catch {
63297
- return false;
63298
- }
63299
- }
63300
- function inspectLauncher(paths, isOurWrapper) {
63301
- let st2;
63302
- try {
63303
- st2 = lstatSync3(paths.wrapperPath);
63304
- } catch {
63305
- return null;
63306
- }
63307
- if (st2.isSymbolicLink()) {
63308
- const raw = readlinkSync2(paths.wrapperPath);
63309
- const target = isAbsolute2(raw) ? raw : resolve3(dirname9(paths.wrapperPath), raw);
63310
- if (isManaged(target, paths, isOurWrapper))
63311
- return null;
63312
- return { kind: "found", bin: target, launcher_restore: { kind: "symlink", target } };
63313
- }
63314
- if (isOurWrapper(paths.wrapperPath))
63315
- return null;
63316
- return { kind: "foreign", path: paths.wrapperPath };
63317
- }
63318
- function walkPath(paths, env3, isOurWrapper) {
63319
- for (const dir of (env3.PATH ?? "").split(":").filter(Boolean)) {
63320
- if (resolve3(dir) === resolve3(paths.binDir))
63321
- continue;
63322
- const candidate = join13(dir, "codex");
63323
- if (isExecutable2(candidate) && !isManaged(candidate, paths, isOurWrapper))
63324
- return candidate;
63325
- }
63326
- return null;
63327
- }
63328
- function resolveUpstream(paths, env3, isOurWrapper, savedBin) {
63329
- const launcher = inspectLauncher(paths, isOurWrapper);
63330
- if (launcher)
63331
- return launcher;
63332
- const current = walkPath(paths, env3, isOurWrapper);
63333
- const bin = current ?? (savedBin && isExecutable2(savedBin) && !isManaged(savedBin, paths, isOurWrapper) ? savedBin : null);
63334
- return bin ? { kind: "found", bin, launcher_restore: { kind: "none" } } : { kind: "not-found" };
63335
- }
63336
- function describeLookup(l) {
63337
- switch (l.kind) {
63338
- case "found":
63339
- return l.bin;
63340
- case "foreign":
63341
- return `${l.path} is a real file we did not write; refusing to overwrite it`;
63342
- case "not-found":
63343
- return "no upstream Codex found (nothing named codex on PATH outside ~/.local/bin, and the launcher there is not a symlink)";
63344
- }
63345
- }
63346
- function readUpstreamVersion(bin, run) {
63347
- const r = run(bin, ["--version"]);
63348
- if (r.status !== 0)
63349
- return null;
63350
- return parseCodexVersionOutput(r.stdout);
63351
- }
63352
- function preserveLauncherRestore(recorded, found) {
63353
- return found.kind === "symlink" ? found : recorded ?? found;
63354
- }
63355
-
63356
63433
  // src/hook/install.ts
63357
63434
  import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
63358
63435
 
@@ -63494,25 +63571,326 @@ function writeState(file2, state) {
63494
63571
  writeFileAtomic(`${file2}${BACKUP_SUFFIX}`, text);
63495
63572
  }
63496
63573
 
63497
- // src/patch/acquire.ts
63498
- import { rmSync as rmSync5 } from "node:fs";
63574
+ // src/ui/UpdatePicker.tsx
63575
+ var import_react38 = __toESM(require_react(), 1);
63499
63576
 
63500
- // src/patch/compile.ts
63501
- 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";
63502
- import { createHash as createHash5 } from "node:crypto";
63503
- import { join as join16 } from "node:path";
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;
63614
+ }
63615
+ if (key.downArrow) {
63616
+ setSelectedIndex((current) => current === selectableItems.length - 1 ? wrapNavigation ? 0 : selectableItems.length - 1 : current + 1);
63617
+ return;
63618
+ }
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
+ }
63504
63680
 
63505
- // src/patch/build.ts
63506
- import { existsSync as existsSync10, lstatSync as lstatSync4, readFileSync as readFileSync9, statSync as statSync3 } from "node:fs";
63507
- import { join as join15 } from "node:path";
63681
+ // src/ui/prompt.ts
63682
+ var import_react37 = __toESM(require_react(), 1);
63508
63683
 
63509
- // src/patch/v8.ts
63510
- import { existsSync as existsSync9 } from "node:fs";
63511
- import { join as join14 } from "node:path";
63512
- function defaultV8Target() {
63513
- const isArm = process.arch === "arm64";
63514
- if (process.platform === "darwin")
63515
- return isArm ? "aarch64-apple-darwin" : "x86_64-apple-darwin";
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();
63724
+ }
63725
+ }
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");
63735
+ });
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."
63757
+ });
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");
63797
+ }
63798
+
63799
+ // src/patch/acquire.ts
63800
+ import { rmSync as rmSync5 } from "node:fs";
63801
+
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";
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";
63890
+ function defaultV8Target() {
63891
+ const isArm = process.arch === "arm64";
63892
+ if (process.platform === "darwin")
63893
+ return isArm ? "aarch64-apple-darwin" : "x86_64-apple-darwin";
63516
63894
  if (process.platform === "linux")
63517
63895
  return isArm ? "aarch64-unknown-linux-gnu" : "x86_64-unknown-linux-gnu";
63518
63896
  return isArm ? "aarch64-pc-windows-msvc" : "x86_64-pc-windows-msvc";
@@ -63539,7 +63917,7 @@ function resolveV8Env(sourceDir, run, log) {
63539
63917
  RUSTY_V8_SRC_BINDING_PATH: process.env.RUSTY_V8_SRC_BINDING_PATH
63540
63918
  };
63541
63919
  }
63542
- const v8Script = join14(sourceDir, "scripts", "codex_package", "v8.py");
63920
+ const v8Script = join13(sourceDir, "scripts", "codex_package", "v8.py");
63543
63921
  if (!existsSync9(v8Script)) {
63544
63922
  return {};
63545
63923
  }
@@ -63611,9 +63989,9 @@ function headCommit(plan, run) {
63611
63989
  }
63612
63990
  function prepareCheckout(plan, run, log) {
63613
63991
  const git = (step, ...args) => must(step, run, log, "git", ["-C", plan.sourceDir, ...args]);
63614
- if (existsSync10(join15(plan.sourceDir, ".git"))) {
63992
+ if (existsSync10(join14(plan.sourceDir, ".git"))) {
63615
63993
  git("fetch", "fetch", "--tags", "--filter=blob:none", "origin");
63616
- const snapshot = join15(plan.sourceDir, SNAPSHOT);
63994
+ const snapshot = join14(plan.sourceDir, SNAPSHOT);
63617
63995
  const st2 = lstatSync4(snapshot, { throwIfNoEntry: false });
63618
63996
  if (st2) {
63619
63997
  const tracked = run("git", ["-C", plan.sourceDir, "ls-files", "--error-unmatch", "--", SNAPSHOT]);
@@ -63641,7 +64019,7 @@ function buildPatched(plan, run, log, which, onStatus) {
63641
64019
  git("apply --check", "apply", "--index", "--check", plan.patchFile);
63642
64020
  git("apply", "apply", "--index", plan.patchFile);
63643
64021
  onStatus?.("patch-done", `Applied ${patchBase} cleanly`);
63644
- const crateDir = join15(plan.sourceDir, "codex-rs");
64022
+ const crateDir = join14(plan.sourceDir, "codex-rs");
63645
64023
  const v8Env = resolveV8Env(plan.sourceDir, run, log);
63646
64024
  onStatus?.("build", "Compiling release binaries (cargo build --release)... Note: this full compile typically takes 10 to 20 minutes.");
63647
64025
  const buildStart = Date.now();
@@ -63650,7 +64028,7 @@ function buildPatched(plan, run, log, which, onStatus) {
63650
64028
  const buildElapsedStr = buildElapsed >= 60 ? `${Math.floor(buildElapsed / 60)}m ${buildElapsed % 60}s` : `${buildElapsed}s`;
63651
64029
  onStatus?.("build-done", `Release binaries compiled (codex, codex-code-mode-host in ${buildElapsedStr})`);
63652
64030
  const [codex, codexCodeModeHost] = TARGETS.map((name) => {
63653
- const bin = join15(crateDir, "target", "release", name);
64031
+ const bin = join14(crateDir, "target", "release", name);
63654
64032
  if (!existsSync10(bin) || statSync3(bin).size === 0) {
63655
64033
  throw new BuildError("cargo build", `cargo exited 0 but ${bin} is missing or empty`);
63656
64034
  }
@@ -63679,7 +64057,7 @@ function platformLabel() {
63679
64057
  }
63680
64058
  function stage(ctx, built) {
63681
64059
  mkdirSync6(ctx.paths.libexecDir, { recursive: true });
63682
- const directory = mkdtempSync2(join16(ctx.paths.libexecDir, STAGING_PREFIX));
64060
+ const directory = mkdtempSync2(join15(ctx.paths.libexecDir, STAGING_PREFIX));
63683
64061
  chmodSync3(directory, 448);
63684
64062
  const sources = {
63685
64063
  codex: built.codex,
@@ -63688,7 +64066,7 @@ function stage(ctx, built) {
63688
64066
  const executables = {};
63689
64067
  try {
63690
64068
  for (const name of GENERATION_EXECUTABLES) {
63691
- const target = join16(directory, name);
64069
+ const target = join15(directory, name);
63692
64070
  copyFileSync3(sources[name], target);
63693
64071
  chmodSync3(target, 493);
63694
64072
  executables[name] = digestOf3(target);
@@ -63706,7 +64084,7 @@ function stage(ctx, built) {
63706
64084
  };
63707
64085
  }
63708
64086
  function prepareCompiled(ctx, upstream, ref, onStatus) {
63709
- const patchFile = join16(ctx.patchesDir, ref.file);
64087
+ const patchFile = join15(ctx.patchesDir, ref.file);
63710
64088
  const patchSha256 = digestOf3(patchFile).sha256;
63711
64089
  const built = buildPatched({ tag: ref.tag, sourceDir: ctx.paths.sourceDir, patchFile }, ctx.run, ctx.log, ctx.which, onStatus);
63712
64090
  onStatus?.("stage", "Staging generation and verifying binaries...");
@@ -63719,6 +64097,7 @@ function prepareCompiled(ctx, upstream, ref, onStatus) {
63719
64097
  source: "compiled",
63720
64098
  cxVersion: VERSION,
63721
64099
  platform: platformLabel(),
64100
+ patchVersion: ref.patchVersion,
63722
64101
  patchSha256,
63723
64102
  upstreamCommit: built.upstreamCommit,
63724
64103
  sourceCommit: SOURCE_COMMIT,
@@ -63731,7 +64110,7 @@ function prepareCompiled(ctx, upstream, ref, onStatus) {
63731
64110
 
63732
64111
  // src/patch/manifest.ts
63733
64112
  import { readFileSync as readFileSync11 } from "node:fs";
63734
- import { join as join17 } from "node:path";
64113
+ import { join as join16 } from "node:path";
63735
64114
  class ManifestError extends Error {
63736
64115
  name = "ManifestError";
63737
64116
  }
@@ -63750,13 +64129,28 @@ var isCandidate = (c) => {
63750
64129
  return parsed !== null && parsed.pre === null;
63751
64130
  };
63752
64131
  function loadManifest(patchesDir) {
63753
- const file2 = join17(patchesDir, "manifest.json");
64132
+ const file2 = join16(patchesDir, "manifest.json");
63754
64133
  try {
63755
64134
  const raw = JSON.parse(readFileSync11(file2, "utf8"));
63756
64135
  const m2 = raw;
63757
- 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);
63758
64137
  if (!ok)
63759
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
+ }
63760
64154
  return m2;
63761
64155
  } catch (e) {
63762
64156
  if (e instanceof ManifestError)
@@ -63772,7 +64166,7 @@ function resolvePatch(m2, v2) {
63772
64166
  const max2 = parseSemver(p2.max);
63773
64167
  return min2 && max2 && compareSemver(v2, min2) >= 0 && compareSemver(v2, max2) <= 0;
63774
64168
  });
63775
- 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;
63776
64170
  }
63777
64171
  function supportedCodexVersions(m2) {
63778
64172
  const versions2 = new Set;
@@ -63798,7 +64192,7 @@ function isCodexVersionSupported(m2, version2) {
63798
64192
  // src/patch/wrapper.ts
63799
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";
63800
64194
  import { randomBytes as randomBytes3 } from "node:crypto";
63801
- import { join as join18 } from "node:path";
64195
+ import { join as join17 } from "node:path";
63802
64196
  var WRAPPER_MARKER = "# cxstatusline-wrapper v1";
63803
64197
  var WRAPPER_MARKER_V2 = "# cxstatusline-wrapper v2";
63804
64198
  var WRAPPER_MARKERS = [WRAPPER_MARKER, WRAPPER_MARKER_V2];
@@ -63857,7 +64251,7 @@ function isSymlink(p2) {
63857
64251
  }
63858
64252
  }
63859
64253
  function stageExecutable(target, write) {
63860
- mkdirSync7(join18(target, ".."), { recursive: true });
64254
+ mkdirSync7(join17(target, ".."), { recursive: true });
63861
64255
  const tmp = `${target}.tmp-${process.pid}`;
63862
64256
  try {
63863
64257
  write(tmp);
@@ -64117,6 +64511,9 @@ async function prebuiltAcquisition(ctx, state, upstream, transport) {
64117
64511
  }
64118
64512
  let prepared;
64119
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
+ }
64120
64517
  prepared = await preparePrebuilt(ctx, expected, transport);
64121
64518
  } catch (e) {
64122
64519
  if (e instanceof ReleaseUnavailableError) {
@@ -64271,6 +64668,7 @@ function renderInstallFailure(outcome, advice) {
64271
64668
  return renderBox(lines, { borderColor: source_default.red, minWidth: 68 });
64272
64669
  }
64273
64670
  // src/ui/progress.ts
64671
+ var import_react39 = __toESM(require_react(), 1);
64274
64672
  function formatBytes2(bytes) {
64275
64673
  if (bytes <= 0)
64276
64674
  return "0 B";
@@ -64303,82 +64701,31 @@ function createInstallProgressTracker(io2, baseTransport = {}) {
64303
64701
  let downloadStart = 0;
64304
64702
  let initialLoaded = 0;
64305
64703
  let lastDownloadUpdate = 0;
64306
- let hasProgressBar = false;
64307
64704
  let lastReportedPct = -1;
64308
- let cursorHidden = false;
64309
- let stdinConfigured = false;
64310
- const hideCursor = () => {
64311
- if (isTTY && !cursorHidden) {
64312
- io2.write("\x1B[?25l");
64313
- cursorHidden = true;
64314
- }
64315
- };
64316
- const showCursor = () => {
64317
- if (isTTY && cursorHidden) {
64318
- io2.write("\x1B[?25h");
64319
- cursorHidden = false;
64320
- }
64321
- };
64322
- const handleStdinData = (data) => {
64323
- const str2 = typeof data === "string" ? data : data.toString("utf8");
64324
- if (str2 === "\x03") {
64325
- cleanupStdin();
64326
- showCursor();
64327
- if (typeof process !== "undefined" && typeof process.kill === "function") {
64328
- process.kill(process.pid, "SIGINT");
64329
- }
64330
- }
64331
- };
64332
- const setupStdin = () => {
64333
- if (!isTTY || stdinConfigured)
64334
- return;
64335
- if (typeof process !== "undefined" && process.stdin?.isTTY && typeof process.stdin.setRawMode === "function") {
64336
- try {
64337
- process.stdin.setRawMode(true);
64338
- process.stdin.resume();
64339
- process.stdin.on("data", handleStdinData);
64340
- stdinConfigured = true;
64341
- } catch {}
64342
- }
64343
- };
64344
- const cleanupStdin = () => {
64345
- if (!stdinConfigured)
64346
- return;
64347
- stdinConfigured = false;
64348
- if (typeof process !== "undefined" && process.stdin) {
64349
- try {
64350
- process.stdin.removeListener("data", handleStdinData);
64351
- if (typeof process.stdin.setRawMode === "function") {
64352
- process.stdin.setRawMode(false);
64353
- }
64354
- process.stdin.pause();
64355
- } catch {}
64356
- }
64357
- };
64358
- const onExit = () => {
64359
- cleanupStdin();
64360
- if (cursorHidden) {
64361
- try {
64362
- io2.write("\x1B[?25h");
64363
- } catch {}
64364
- cursorHidden = false;
64365
- }
64366
- };
64367
- const proc = typeof process !== "undefined" ? process : null;
64368
- if (proc?.once && isTTY) {
64369
- proc.once("exit", onExit);
64370
- proc.once("SIGINT", onExit);
64371
- proc.once("SIGTERM", onExit);
64372
- }
64705
+ let view;
64373
64706
  const clearProgressLine = () => {
64374
- if (hasProgressBar && isTTY) {
64375
- io2.write("\r\x1B[2K");
64376
- hasProgressBar = false;
64377
- }
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
+ });
64378
64727
  };
64379
64728
  const onProgress = (loaded, total) => {
64380
- hideCursor();
64381
- setupStdin();
64382
64729
  const now2 = Date.now();
64383
64730
  if (!downloadStart) {
64384
64731
  downloadStart = now2;
@@ -64396,12 +64743,13 @@ function createInstallProgressTracker(io2, baseTransport = {}) {
64396
64743
  const ratio = Math.min(1, loaded / total);
64397
64744
  const pct = Math.floor(ratio * 100);
64398
64745
  if (isTTY) {
64399
- const bar = renderProgressBar(ratio, 24);
64400
64746
  const loadedStr = formatBytes2(loaded);
64401
64747
  const totalStr = formatBytes2(total);
64402
- const text = `\r\x1B[2K ${bar} ${source_default.bold(String(pct).padStart(3))}% ${loadedStr} / ${totalStr} (${source_default.dim(speedStr)})`;
64403
- io2.write(text);
64404
- 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);
64405
64753
  } else {
64406
64754
  const milestone = Math.floor(pct / 25) * 25;
64407
64755
  if (milestone > lastReportedPct && milestone > 0) {
@@ -64411,8 +64759,7 @@ function createInstallProgressTracker(io2, baseTransport = {}) {
64411
64759
  }
64412
64760
  } else {
64413
64761
  if (isTTY) {
64414
- io2.write(`\r\x1B[2K ${symbols.activeBullet} ${formatBytes2(loaded)} downloaded (${source_default.dim(speedStr)})`);
64415
- hasProgressBar = true;
64762
+ showProgress(`${symbols.activeBullet} ${formatBytes2(loaded)} downloaded (${source_default.dim(speedStr)})`);
64416
64763
  }
64417
64764
  }
64418
64765
  };
@@ -64503,16 +64850,7 @@ function createInstallProgressTracker(io2, baseTransport = {}) {
64503
64850
  };
64504
64851
  return {
64505
64852
  transport,
64506
- finish: () => {
64507
- if (proc?.removeListener) {
64508
- proc.removeListener("exit", onExit);
64509
- proc.removeListener("SIGINT", onExit);
64510
- proc.removeListener("SIGTERM", onExit);
64511
- }
64512
- cleanupStdin();
64513
- clearProgressLine();
64514
- showCursor();
64515
- }
64853
+ finish: clearProgressLine
64516
64854
  };
64517
64855
  }
64518
64856
 
@@ -64571,17 +64909,11 @@ function fallbackAdvice(ctx, version2) {
64571
64909
  lines.push(`Tracking issue: ${url2}`);
64572
64910
  return lines;
64573
64911
  }
64574
- function report(ctx, outcome) {
64575
- ctx.say(describeOutcome(outcome));
64576
- if (outcome.kind === "unavailable")
64577
- for (const line of fallbackAdvice(ctx, outcome.version))
64578
- ctx.say(line);
64579
- }
64580
64912
  function runPatch(ctx, opts, transport = {}) {
64581
64913
  ctx.say(renderInstallHeader(true));
64582
64914
  const progress = createInstallProgressTracker({
64583
64915
  isTTY: process.stdout?.isTTY,
64584
- write: (s3) => process.stdout.write(s3),
64916
+ stdout: process.stdout,
64585
64917
  say: (l) => ctx.say(l)
64586
64918
  }, transport);
64587
64919
  return runAcquisition(ctx, { source: "compiled", force: opts.force }, progress.transport).finally(() => {
@@ -64592,7 +64924,7 @@ async function runInstall(ctx, opts, transport = {}) {
64592
64924
  ctx.say(renderInstallHeader(opts.compile));
64593
64925
  const progress = createInstallProgressTracker({
64594
64926
  isTTY: process.stdout?.isTTY,
64595
- write: (s3) => process.stdout.write(s3),
64927
+ stdout: process.stdout,
64596
64928
  say: (l) => ctx.say(l)
64597
64929
  }, transport);
64598
64930
  let outcome;
@@ -64648,18 +64980,6 @@ async function probeUpstreamLatest(fetchFn) {
64648
64980
  return null;
64649
64981
  }
64650
64982
  }
64651
- async function probePrebuiltExists(targetCodexVersion, cxVersionOrFetch, fetchFnOrBaseUrl, baseUrl) {
64652
- const fetchFn = typeof cxVersionOrFetch === "function" ? cxVersionOrFetch : fetchFnOrBaseUrl ?? globalThis.fetch;
64653
- const resolvedBaseUrl = typeof cxVersionOrFetch === "function" ? typeof fetchFnOrBaseUrl === "string" ? fetchFnOrBaseUrl : baseUrl : baseUrl;
64654
- try {
64655
- const tag = releaseTag(targetCodexVersion);
64656
- const url2 = resolvedBaseUrl ? `${resolvedBaseUrl}/${tag}/manifest.json` : `https://github.com/adrijshikhar/cxstatusline/releases/download/${tag}/manifest.json`;
64657
- const res = await fetchFn(url2, { method: "HEAD", signal: AbortSignal.timeout(5000) });
64658
- return res.ok || res.status === 302 || res.status === 301;
64659
- } catch {
64660
- return false;
64661
- }
64662
- }
64663
64983
  async function probeRemoteCandidate(targetCodexVersion, fetchFnOrBaseUrl, baseUrl) {
64664
64984
  const fetchFn = typeof fetchFnOrBaseUrl === "function" ? fetchFnOrBaseUrl : globalThis.fetch;
64665
64985
  const resolvedBaseUrl = typeof fetchFnOrBaseUrl === "string" ? fetchFnOrBaseUrl : baseUrl;
@@ -64676,115 +64996,190 @@ async function probeRemoteCandidate(targetCodexVersion, fetchFnOrBaseUrl, baseUr
64676
64996
  return null;
64677
64997
  }
64678
64998
  }
64679
- async function runUpdate(ctx, optsOrTransport = {}, maybeTransport) {
64680
- const opts = "compile" in optsOrTransport || "force" in optsOrTransport ? optsOrTransport : {};
64681
- const transport = "baseUrl" in optsOrTransport || "fetch" in optsOrTransport ? optsOrTransport : maybeTransport ?? {};
64682
- const state = loadState(ctx);
64683
- const located = upstreamFor(ctx, state);
64684
- if ("reason" in located) {
64685
- 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.");
64686
65005
  return 1;
64687
65006
  }
64688
- const current = readUpstreamVersion(located.bin, ctx.run);
64689
- const fetchFn = transport.fetch ?? fetch;
64690
- if (current && !opts.force && !opts.compile) {
64691
- const latest = await probeUpstreamLatest(fetchFn);
64692
- if (latest && latest !== current.raw) {
64693
- const available = await probePrebuiltExists(latest, fetchFn, transport.baseUrl);
64694
- if (!available) {
64695
- ctx.say(`Warning: Upstream Codex update available: ${current.raw} -> ${latest}.`);
64696
- ctx.say(`However, cxstatusline has not yet published prebuilt binaries for Codex ${latest}.`);
64697
- ctx.say("Updating now will replace your patched launcher with stock Codex.");
64698
- ctx.say("");
64699
- ctx.say("Options:");
64700
- ctx.say(" - Wait until cxstatusline publishes prebuilt binaries for this version.");
64701
- ctx.say(" - Update and compile from source: cxstatusline update --compile");
64702
- ctx.say(" - Update to stock Codex anyway: cxstatusline update --force");
64703
- return 1;
64704
- }
64705
- } else if (latest && latest === current.raw) {
64706
- 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.");
64707
65017
  return 0;
64708
65018
  }
65019
+ if (action === "compile")
65020
+ return runInstall(ctx, { compile: true, codexVersion: target }, transport);
64709
65021
  }
64710
- ctx.say(`running upstream updater: ${located.bin} update`);
64711
- const r = ctx.run(located.bin, ["update"], { interactive: true });
64712
- if (r.status !== 0) {
64713
- ctx.say(`upstream updater exited ${String(r.status)}; see its output above. Not installing.`);
64714
- return 1;
64715
- }
64716
- const source = opts.compile ? "compiled" : "prebuilt";
64717
- const progress = createInstallProgressTracker({
64718
- isTTY: process.stdout?.isTTY,
64719
- write: (s3) => process.stdout.write(s3),
64720
- say: (l) => ctx.say(l)
64721
- }, transport);
64722
- let outcome;
64723
- try {
64724
- outcome = await runAcquisition(ctx, { source, force: true }, progress.transport);
64725
- } finally {
64726
- progress.finish();
64727
- }
64728
- report(ctx, outcome);
64729
- return outcome.kind === "installed" ? 0 : 1;
65022
+ return runInstall(ctx, { compile: opts.compile ?? false, codexVersion: target }, transport);
64730
65023
  }
64731
65024
  function appendLog(file2, line) {
64732
- mkdirSync8(join19(file2, ".."), { recursive: true });
65025
+ mkdirSync8(join18(file2, ".."), { recursive: true });
64733
65026
  appendFileSync(file2, `${new Date().toISOString()} ${line}
64734
65027
  `);
64735
65028
  }
64736
65029
 
64737
65030
  // src/ui/prompt-version.ts
64738
- import { createInterface } from "node:readline";
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
64739
65152
  async function promptCodexVersion(options) {
64740
- const { supportedVersions, isTTY = false, say = (s3) => console.log(s3) } = options;
65153
+ const { supportedVersions, prebuiltVersions, isTTY = false, say = (s3) => console.log(s3) } = options;
64741
65154
  if (supportedVersions.length === 0) {
64742
65155
  throw new Error("No supported Codex versions available.");
64743
65156
  }
64744
- const defaultVersion = options.defaultVersion && supportedVersions.includes(options.defaultVersion) ? options.defaultVersion : supportedVersions[0];
64745
- if (!isTTY) {
64746
- return defaultVersion;
64747
- }
64748
- const defaultIndex = supportedVersions.indexOf(defaultVersion) + 1;
64749
- say(`
64750
- Select Codex version to install:`);
64751
- supportedVersions.forEach((v2, idx) => {
64752
- const isDef = v2 === defaultVersion;
64753
- say(` ${idx + 1}) ${v2}${isDef ? " (recommended / default)" : ""}`);
64754
- });
64755
- const askFn = options.ask ?? defaultAsk;
64756
- while (true) {
64757
- const raw = (await askFn(`Enter choice [1-${supportedVersions.length}] (default ${defaultIndex}): `)).trim();
64758
- if (raw === "") {
64759
- return defaultVersion;
64760
- }
64761
- const num2 = Number.parseInt(raw, 10);
64762
- if (!Number.isNaN(num2) && num2 >= 1 && num2 <= supportedVersions.length) {
64763
- return supportedVersions[num2 - 1];
64764
- }
64765
- if (supportedVersions.includes(raw)) {
64766
- return raw;
64767
- }
64768
- say(`Invalid selection "${raw}". Please enter a number between 1 and ${supportedVersions.length}.`);
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];
64769
65164
  }
64770
- }
64771
- function defaultAsk(question) {
64772
- const rl = createInterface({
64773
- input: process.stdin,
64774
- output: process.stdout
64775
- });
64776
- return new Promise((resolve4) => {
64777
- rl.question(question, (answer) => {
64778
- rl.close();
64779
- resolve4(answer);
64780
- });
64781
- });
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;
64782
65177
  }
64783
65178
 
64784
65179
  // src/hook/run.ts
64785
65180
  import { appendFileSync as appendFileSync2, closeSync as closeSync3, existsSync as existsSync12, mkdirSync as mkdirSync9, openSync as openSync3 } from "node:fs";
64786
65181
  import { spawn as spawn2 } from "node:child_process";
64787
- import { dirname as dirname10 } from "node:path";
65182
+ import { dirname as dirname9 } from "node:path";
64788
65183
  var HOOK_SOURCES = ["startup", "resume", "clear"];
64789
65184
  function parseHookInput(stdin) {
64790
65185
  try {
@@ -64911,7 +65306,7 @@ function realHookDeps() {
64911
65306
  spawnDetached(cxBin, args, logFile) {
64912
65307
  let fd;
64913
65308
  try {
64914
- mkdirSync9(dirname10(logFile), { recursive: true });
65309
+ mkdirSync9(dirname9(logFile), { recursive: true });
64915
65310
  fd = openSync3(logFile, "a");
64916
65311
  const child = spawn2(cxBin, args, { detached: true, stdio: ["ignore", fd, fd], env: process.env });
64917
65312
  child.on("error", (err) => {
@@ -64935,7 +65330,7 @@ function realHookDeps() {
64935
65330
 
64936
65331
  // src/commands/doctor.ts
64937
65332
  import { existsSync as existsSync14, lstatSync as lstatSync6, readFileSync as readFileSync14, readlinkSync as readlinkSync3, readdirSync as readdirSync3 } from "node:fs";
64938
- import { join as join21 } from "node:path";
65333
+ import { join as join20 } from "node:path";
64939
65334
 
64940
65335
  // src/utils/format.ts
64941
65336
  function formatDuration2(ms2) {
@@ -64953,11 +65348,11 @@ function formatDuration2(ms2) {
64953
65348
  // src/commands/doctor-generation.ts
64954
65349
  import { createHash as createHash6 } from "node:crypto";
64955
65350
  import { existsSync as existsSync13, readFileSync as readFileSync13 } from "node:fs";
64956
- 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";
64957
65352
  var line = (key, value, ok = null) => ({ key, value, ok });
64958
65353
  var NO_GENERATION = "n/a (no active generation)";
64959
65354
  function resolvePointerTarget(paths, raw) {
64960
- return isAbsolute3(raw) ? raw : resolve4(dirname11(paths.currentGeneration), raw);
65355
+ return isAbsolute3(raw) ? raw : resolve4(dirname10(paths.currentGeneration), raw);
64961
65356
  }
64962
65357
  function computeGenerationLine(paths, pointer) {
64963
65358
  const dir = activeGeneration(paths);
@@ -65032,7 +65427,7 @@ function upstreamCommitLine(record2) {
65032
65427
  function digestLine(key, label, record2, dir) {
65033
65428
  if (!record2 || !dir)
65034
65429
  return line(label, NO_GENERATION, null);
65035
- const file2 = join20(dir, key);
65430
+ const file2 = join19(dir, key);
65036
65431
  if (!existsSync13(file2))
65037
65432
  return line(label, "missing", false);
65038
65433
  let buf;
@@ -65050,7 +65445,7 @@ function digestLine(key, label, record2, dir) {
65050
65445
  function codexVersionLine(ctx, record2, dir) {
65051
65446
  if (!record2 || !dir)
65052
65447
  return line("codex_version", NO_GENERATION, null);
65053
- const bin = join20(dir, "codex");
65448
+ const bin = join19(dir, "codex");
65054
65449
  if (!existsSync13(bin))
65055
65450
  return line("codex_version", "missing", false);
65056
65451
  let result2;
@@ -65073,7 +65468,7 @@ function legalLine(record2, dir) {
65073
65468
  return line("legal", "n/a (compiled build)", null);
65074
65469
  if (!dir)
65075
65470
  return line("legal", NO_GENERATION, null);
65076
- const missing = GENERATION_LEGAL_FILES.filter((f2) => !existsSync13(join20(dir, f2)));
65471
+ const missing = GENERATION_LEGAL_FILES.filter((f2) => !existsSync13(join19(dir, f2)));
65077
65472
  return missing.length === 0 ? line("legal", "present", true) : line("legal", `missing: ${missing.join(", ")}`, false);
65078
65473
  }
65079
65474
  function generationDetailLines(ctx, status) {
@@ -65297,7 +65692,7 @@ function commandCacheLine(ctx) {
65297
65692
  let oldestMtime = Infinity;
65298
65693
  for (const f2 of entries) {
65299
65694
  try {
65300
- const st2 = lstatSync6(join21(dir, f2));
65695
+ const st2 = lstatSync6(join20(dir, f2));
65301
65696
  if (st2.mtimeMs < oldestMtime)
65302
65697
  oldestMtime = st2.mtimeMs;
65303
65698
  } catch {}
@@ -65351,6 +65746,25 @@ async function codexTargetLine(ctx, effectivePatchedFrom, opts) {
65351
65746
  return line2("codex_target", `${target} available (active: ${effectivePatchedFrom}; prebuilt live on GitHub; run cxstatusline install to update)`, null);
65352
65747
  }
65353
65748
  if (remote?.available === false) {
65749
+ let intermediate = null;
65750
+ if (opts?.fetchPrebuilts || opts?.probe !== false && opts?.probeFn === undefined) {
65751
+ try {
65752
+ const fetchFn = (url2, init) => fetch(url2, { ...init, signal: AbortSignal.timeout(2000) });
65753
+ const prebuilts = await (opts?.fetchPrebuilts ?? fetchPublishedPrebuiltVersions)(fetchFn);
65754
+ const intermediatePrebuilt = prebuilts.find((v2) => {
65755
+ const s3 = parseSemver(v2);
65756
+ return s3 !== null && parsedActive !== null && parsedTarget !== null && compareSemver(s3, parsedActive) > 0 && compareSemver(s3, parsedTarget) < 0;
65757
+ });
65758
+ if (intermediatePrebuilt) {
65759
+ intermediate = intermediatePrebuilt;
65760
+ }
65761
+ } catch {
65762
+ intermediate = null;
65763
+ }
65764
+ }
65765
+ if (intermediate) {
65766
+ return line2("codex_target", `${target} supported (active: ${effectivePatchedFrom}; prebuilt pending; ${intermediate} prebuilt available on GitHub)`, null);
65767
+ }
65354
65768
  return line2("codex_target", `${target} supported (active: ${effectivePatchedFrom}; prebuilt pending; run cxstatusline install --compile)`, null);
65355
65769
  }
65356
65770
  return line2("codex_target", `${target} supported (active: ${effectivePatchedFrom}; run cxstatusline install to update)`, null);
@@ -65380,6 +65794,7 @@ async function doctorReport(ctx, opts) {
65380
65794
  line2("settings", `${ctx.paths.settingsFile} ${existsSync14(ctx.paths.settingsFile) ? "present" : "absent (written on first render)"}`),
65381
65795
  upstreamLine(ctx, upstreamBin, upstream?.raw ?? null, lookupNote),
65382
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}`),
65383
65798
  line2("patched_from", state.patched_from ?? "never"),
65384
65799
  line2("policy", state.policy),
65385
65800
  codexTarget,
@@ -65449,7 +65864,7 @@ function runPolicy(ctx, argv, io2) {
65449
65864
 
65450
65865
  // src/commands/revert.ts
65451
65866
  import { existsSync as existsSync15, lstatSync as lstatSync7, readdirSync as readdirSync4, rmSync as rmSync6, symlinkSync as symlinkSync2 } from "node:fs";
65452
- import { join as join22 } from "node:path";
65867
+ import { join as join21 } from "node:path";
65453
65868
  function safeIsSymlink(p2) {
65454
65869
  try {
65455
65870
  return lstatSync7(p2).isSymbolicLink();
@@ -65496,7 +65911,7 @@ function removeStagingDebris(ctx, actions) {
65496
65911
  return;
65497
65912
  const debris = readdirSync4(libexecDir).filter((n) => OWNED_LIBEXEC_PREFIXES.some((p2) => n.startsWith(p2)));
65498
65913
  for (const name of debris)
65499
- rmSync6(join22(libexecDir, name), { recursive: true, force: true });
65914
+ rmSync6(join21(libexecDir, name), { recursive: true, force: true });
65500
65915
  if (debris.length > 0) {
65501
65916
  actions.push(`removed ${debris.length} leftover staging entr${debris.length === 1 ? "y" : "ies"} from ${libexecDir}`);
65502
65917
  }
@@ -65546,7 +65961,7 @@ function revertLocked(ctx) {
65546
65961
 
65547
65962
  // src/tui/App.tsx
65548
65963
  import { readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
65549
- var import_react46 = __toESM(require_react(), 1);
65964
+ var import_react52 = __toESM(require_react(), 1);
65550
65965
 
65551
65966
  // src/utils/presets.ts
65552
65967
  function isRecord2(value) {
@@ -65567,146 +65982,52 @@ function trimSeparators(items) {
65567
65982
  result2.pop();
65568
65983
  return result2;
65569
65984
  }
65570
- function normalizeImportedItems(items) {
65571
- const accepted = [];
65572
- const omittedTypes = [];
65573
- for (const raw of items) {
65574
- if (!isRecord2(raw) || typeof raw.type !== "string")
65575
- continue;
65576
- const sourceType = raw.type;
65577
- const type = sourceType;
65578
- if (!WidgetTypeSchema.safeParse(type).success) {
65579
- addOnce(omittedTypes, sourceType);
65580
- continue;
65581
- }
65582
- const parsed = WidgetItemSchema.safeParse({ ...raw, type });
65583
- if (parsed.success)
65584
- accepted.push(parsed.data);
65585
- }
65586
- return { items: trimSeparators(accepted), omittedTypes };
65587
- }
65588
- function previewImport(raw) {
65589
- if (!isRecord2(raw) || !Array.isArray(raw.lines) || raw.lines.length < 1 || raw.lines.length > 3) {
65590
- throw new Error("A preset must contain one to three lines.");
65591
- }
65592
- const omittedTypes = [];
65593
- const lines = raw.lines.map((line3) => {
65594
- if (!Array.isArray(line3))
65595
- throw new Error("Each preset line must be an array.");
65596
- const normalized = normalizeImportedItems(line3);
65597
- for (const type of normalized.omittedTypes)
65598
- addOnce(omittedTypes, type);
65599
- return normalized.items;
65600
- });
65601
- const parsed = SettingsSchema.safeParse({ ...raw, version: CURRENT_VERSION, lines });
65602
- if (!parsed.success)
65603
- throw new Error(`Invalid preset: ${parsed.error.issues[0]?.message ?? "settings validation failed"}`);
65604
- return { settings: parsed.data, omittedTypes };
65605
- }
65606
- function exportPreset(settings) {
65607
- return `${JSON.stringify(SettingsSchema.parse(settings), null, 2)}
65608
- `;
65609
- }
65610
-
65611
- // src/tui/components/ColorMenu.tsx
65612
- var import_react38 = __toESM(require_react(), 1);
65613
-
65614
- // src/tui/components/List.tsx
65615
- var import_react35 = __toESM(require_react(), 1);
65616
- var jsx_dev_runtime10 = __toESM(require_jsx_dev_runtime(), 1);
65617
- function List({
65618
- items,
65619
- onSelect,
65620
- onSelectionChange,
65621
- initialSelection = 0,
65622
- showBackButton = false,
65623
- color,
65624
- wrapNavigation = true,
65625
- ...boxProps
65626
- }) {
65627
- const [selectedIndex, setSelectedIndex] = import_react35.useState(initialSelection);
65628
- const latestOnSelectionChange = import_react35.useRef(onSelectionChange);
65629
- const displayedItems = import_react35.useMemo(() => showBackButton ? [...items, "-", { label: "← Back", value: "back" }] : [...items], [items, showBackButton]);
65630
- const selectableItems = displayedItems.filter((item) => item !== "-" && !item.disabled);
65631
- const selectedItem = selectableItems[selectedIndex];
65632
- const actualIndex = displayedItems.findIndex((item) => item === selectedItem);
65633
- import_react35.useEffect(() => {
65634
- latestOnSelectionChange.current = onSelectionChange;
65635
- }, [onSelectionChange]);
65636
- import_react35.useEffect(() => {
65637
- setSelectedIndex(Math.min(initialSelection, Math.max(0, selectableItems.length - 1)));
65638
- }, [initialSelection, selectableItems.length]);
65639
- import_react35.useEffect(() => {
65640
- if (selectedItem)
65641
- latestOnSelectionChange.current?.(selectedItem.value, selectedIndex);
65642
- }, [selectedIndex, selectedItem]);
65643
- use_input_default((_2, key) => {
65644
- if (!selectableItems.length)
65645
- return;
65646
- if (key.upArrow) {
65647
- setSelectedIndex((current) => current === 0 ? wrapNavigation ? selectableItems.length - 1 : 0 : current - 1);
65648
- return;
65649
- }
65650
- if (key.downArrow) {
65651
- setSelectedIndex((current) => current === selectableItems.length - 1 ? wrapNavigation ? 0 : selectableItems.length - 1 : current + 1);
65652
- return;
65653
- }
65654
- if (key.return && selectedItem)
65655
- onSelect(selectedItem.value, selectedIndex);
65656
- });
65657
- return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
65658
- flexDirection: "column",
65659
- ...boxProps,
65660
- children: [
65661
- displayedItems.map((item, index) => {
65662
- if (item === "-")
65663
- return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
65664
- children: " "
65665
- }, index, false, undefined, this);
65666
- return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(ListItem, {
65667
- isSelected: index === actualIndex,
65668
- ...color && { color },
65669
- ...item.disabled !== undefined && { disabled: item.disabled },
65670
- ...item.props,
65671
- children: [
65672
- /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
65673
- children: item.label
65674
- }, undefined, false, undefined, this),
65675
- item.sublabel && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
65676
- dimColor: index !== actualIndex,
65677
- children: ` ${item.sublabel}`
65678
- }, undefined, false, undefined, this)
65679
- ]
65680
- }, item.value, true, undefined, this);
65681
- }),
65682
- selectedItem?.description && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
65683
- marginTop: 1,
65684
- paddingLeft: 2,
65685
- children: /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
65686
- dimColor: true,
65687
- wrap: "wrap",
65688
- children: selectedItem.description
65689
- }, undefined, false, undefined, this)
65690
- }, undefined, false, undefined, this)
65691
- ]
65692
- }, undefined, true, undefined, this);
65985
+ function normalizeImportedItems(items) {
65986
+ const accepted = [];
65987
+ const omittedTypes = [];
65988
+ for (const raw of items) {
65989
+ if (!isRecord2(raw) || typeof raw.type !== "string")
65990
+ continue;
65991
+ const sourceType = raw.type;
65992
+ const type = sourceType;
65993
+ if (!WidgetTypeSchema.safeParse(type).success) {
65994
+ addOnce(omittedTypes, sourceType);
65995
+ continue;
65996
+ }
65997
+ const parsed = WidgetItemSchema.safeParse({ ...raw, type });
65998
+ if (parsed.success)
65999
+ accepted.push(parsed.data);
66000
+ }
66001
+ return { items: trimSeparators(accepted), omittedTypes };
65693
66002
  }
65694
- function ListItem({ children, isSelected, color = "green", disabled, ...boxProps }) {
65695
- return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
65696
- ...boxProps,
65697
- children: /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
65698
- ...isSelected && { color },
65699
- ...disabled && { dimColor: true },
65700
- children: [
65701
- isSelected ? "▶ " : " ",
65702
- children
65703
- ]
65704
- }, undefined, true, undefined, this)
65705
- }, undefined, false, undefined, this);
66003
+ function previewImport(raw) {
66004
+ if (!isRecord2(raw) || !Array.isArray(raw.lines) || raw.lines.length < 1 || raw.lines.length > 3) {
66005
+ throw new Error("A preset must contain one to three lines.");
66006
+ }
66007
+ const omittedTypes = [];
66008
+ const lines = raw.lines.map((line3) => {
66009
+ if (!Array.isArray(line3))
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;
66015
+ });
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 };
66020
+ }
66021
+ function exportPreset(settings) {
66022
+ return `${JSON.stringify(SettingsSchema.parse(settings), null, 2)}
66023
+ `;
65706
66024
  }
65707
66025
 
66026
+ // src/tui/components/ColorMenu.tsx
66027
+ var import_react44 = __toESM(require_react(), 1);
66028
+
65708
66029
  // src/tui/components/ConfirmDialog.tsx
65709
- var jsx_dev_runtime11 = __toESM(require_jsx_dev_runtime(), 1);
66030
+ var jsx_dev_runtime13 = __toESM(require_jsx_dev_runtime(), 1);
65710
66031
  var OPTIONS = [
65711
66032
  { label: "Yes", value: true },
65712
66033
  { label: "No", value: false }
@@ -65716,18 +66037,18 @@ function ConfirmDialog({ message, onConfirm, onCancel, inline = false }) {
65716
66037
  if (key.escape)
65717
66038
  onCancel();
65718
66039
  });
65719
- const list = /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(List, {
66040
+ const list = /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(List, {
65720
66041
  items: OPTIONS,
65721
66042
  color: "cyan",
65722
66043
  onSelect: (confirmed) => confirmed ? onConfirm() : onCancel()
65723
66044
  }, undefined, false, undefined, this);
65724
- return inline ? list : /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
66045
+ return inline ? list : /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
65725
66046
  flexDirection: "column",
65726
66047
  children: [
65727
- message && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
66048
+ message && /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
65728
66049
  children: message
65729
66050
  }, undefined, false, undefined, this),
65730
- /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
66051
+ /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
65731
66052
  marginTop: 1,
65732
66053
  children: list
65733
66054
  }, undefined, false, undefined, this)
@@ -65736,14 +66057,14 @@ function ConfirmDialog({ message, onConfirm, onCancel, inline = false }) {
65736
66057
  }
65737
66058
 
65738
66059
  // src/tui/components/ItemsEditor.tsx
65739
- var import_react37 = __toESM(require_react(), 1);
66060
+ var import_react43 = __toESM(require_react(), 1);
65740
66061
 
65741
66062
  // src/tui/components/HideStatesEditor.tsx
65742
- var import_react36 = __toESM(require_react(), 1);
65743
- 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);
65744
66065
  var HideStatesEditor = ({ widget, states, onComplete, onCancel }) => {
65745
- const [selectedIndex, setSelectedIndex] = import_react36.useState(0);
65746
- 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));
65747
66068
  use_input_default((input2, key) => {
65748
66069
  if (key.return) {
65749
66070
  onComplete(setEnabledHideStates(widget, states, enabledKeys));
@@ -65760,35 +66081,35 @@ var HideStatesEditor = ({ widget, states, onComplete, onCancel }) => {
65760
66081
  }
65761
66082
  }
65762
66083
  });
65763
- return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
66084
+ return /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
65764
66085
  flexDirection: "column",
65765
66086
  children: [
65766
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
66087
+ /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
65767
66088
  bold: true,
65768
66089
  children: "Hide"
65769
66090
  }, undefined, false, undefined, this),
65770
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
66091
+ /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
65771
66092
  dimColor: true,
65772
66093
  children: "↑↓ select, Space toggle, Enter save, ESC cancel"
65773
66094
  }, undefined, false, undefined, this),
65774
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
66095
+ /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
65775
66096
  marginTop: 1,
65776
66097
  flexDirection: "column",
65777
66098
  children: states.map((state, index) => {
65778
66099
  const isSelected = index === selectedIndex;
65779
66100
  const isEnabled = enabledKeys.includes(state.key);
65780
- return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
66101
+ return /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
65781
66102
  flexDirection: "row",
65782
66103
  flexWrap: "nowrap",
65783
66104
  children: [
65784
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
66105
+ /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
65785
66106
  width: 3,
65786
- children: /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
66107
+ children: /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
65787
66108
  color: isSelected ? "green" : undefined,
65788
66109
  children: isSelected ? "▶ " : " "
65789
66110
  }, undefined, false, undefined, this)
65790
66111
  }, undefined, false, undefined, this),
65791
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
66112
+ /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
65792
66113
  color: isSelected ? "green" : undefined,
65793
66114
  children: `[${isEnabled ? "x" : " "}] ${state.label}`
65794
66115
  }, undefined, false, undefined, this)
@@ -66037,7 +66358,7 @@ function handleNormalInputMode({
66037
66358
  }
66038
66359
 
66039
66360
  // src/tui/components/ItemsEditor.tsx
66040
- var jsx_dev_runtime13 = __toESM(require_jsx_dev_runtime(), 1);
66361
+ var jsx_dev_runtime15 = __toESM(require_jsx_dev_runtime(), 1);
66041
66362
  function displayWidgetType(type) {
66042
66363
  if (type === "flex-separator")
66043
66364
  return "Flex Separator";
@@ -66088,13 +66409,13 @@ function newWidget(type) {
66088
66409
  };
66089
66410
  }
66090
66411
  function ItemsEditor({ widgets, onUpdate, onBack, lineNumber, settings: _settings }) {
66091
- const [selectedIndex, setSelectedIndex] = import_react37.useState(0);
66092
- const [moveMode, setMoveMode] = import_react37.useState(false);
66093
- const [showClearConfirm, setShowClearConfirm] = import_react37.useState(false);
66094
- const [widgetPicker, setWidgetPicker] = import_react37.useState(null);
66095
- const [customEditor, setCustomEditor] = import_react37.useState(null);
66096
- const widgetCatalog = import_react37.useMemo(buildCatalog, []);
66097
- 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]);
66098
66419
  const openWidgetPicker = (action) => {
66099
66420
  const selectedType = action === "change" ? widgets[selectedIndex]?.type ?? null : null;
66100
66421
  setWidgetPicker(normalizePickerState({
@@ -66151,7 +66472,7 @@ function ItemsEditor({ widgets, onUpdate, onBack, lineNumber, settings: _setting
66151
66472
  });
66152
66473
  });
66153
66474
  if (customEditor?.action === EDIT_HIDE_STATES_ACTION) {
66154
- return /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(HideStatesEditor, {
66475
+ return /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(HideStatesEditor, {
66155
66476
  widget: customEditor.widget,
66156
66477
  states: customEditor.impl.getHideableStates?.() ?? [],
66157
66478
  onComplete: (updated) => {
@@ -66171,15 +66492,15 @@ function ItemsEditor({ widgets, onUpdate, onBack, lineNumber, settings: _setting
66171
66492
  },
66172
66493
  onCancel: () => setCustomEditor(null)
66173
66494
  });
66174
- return editor ?? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66495
+ return editor ?? /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66175
66496
  children: "Unknown editor"
66176
66497
  }, undefined, false, undefined, this);
66177
66498
  }
66178
66499
  if (showClearConfirm) {
66179
- return /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
66500
+ return /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
66180
66501
  flexDirection: "column",
66181
66502
  children: [
66182
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66503
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66183
66504
  bold: true,
66184
66505
  children: [
66185
66506
  "Clear every widget from Line ",
@@ -66187,7 +66508,7 @@ function ItemsEditor({ widgets, onUpdate, onBack, lineNumber, settings: _setting
66187
66508
  "?"
66188
66509
  ]
66189
66510
  }, undefined, true, undefined, this),
66190
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(ConfirmDialog, {
66511
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(ConfirmDialog, {
66191
66512
  inline: true,
66192
66513
  onConfirm: () => {
66193
66514
  onUpdate([]);
@@ -66203,36 +66524,36 @@ function ItemsEditor({ widgets, onUpdate, onBack, lineNumber, settings: _setting
66203
66524
  const topLevelSearch = widgetPicker.level === "category" && widgetPicker.categoryQuery.trim().length > 0;
66204
66525
  const query = topLevelSearch ? widgetPicker.categoryQuery : widgetPicker.widgetQuery;
66205
66526
  const entries = filterWidgetCatalog(widgetCatalog, topLevelSearch ? "All" : widgetPicker.selectedCategory ?? "All", query);
66206
- return /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
66527
+ return /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
66207
66528
  flexDirection: "column",
66208
66529
  children: [
66209
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66530
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66210
66531
  bold: true,
66211
66532
  children: widgetPicker.action === "change" ? "Change Widget" : "Add Widget"
66212
66533
  }, undefined, false, undefined, this),
66213
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66534
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66214
66535
  dimColor: true,
66215
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"
66216
66537
  }, undefined, false, undefined, this),
66217
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66538
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66218
66539
  children: `Search: ${query}`
66219
66540
  }, undefined, false, undefined, this),
66220
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
66541
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
66221
66542
  marginTop: 1,
66222
66543
  flexDirection: "column",
66223
- 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, {
66224
66545
  ...category === widgetPicker.selectedCategory && { color: "green" },
66225
66546
  children: [
66226
66547
  category === widgetPicker.selectedCategory ? "▶ " : " ",
66227
66548
  category
66228
66549
  ]
66229
- }, 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, {
66230
66551
  ...entry.type === widgetPicker.selectedType && { color: "green" },
66231
66552
  children: [
66232
66553
  entry.type === widgetPicker.selectedType ? "▶ " : " ",
66233
66554
  entry.displayName
66234
66555
  ]
66235
- }, entry.type, true, undefined, this)) : /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66556
+ }, entry.type, true, undefined, this)) : /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66236
66557
  dimColor: true,
66237
66558
  children: "No widgets match this search."
66238
66559
  }, undefined, false, undefined, this)
@@ -66243,33 +66564,33 @@ function ItemsEditor({ widgets, onUpdate, onBack, lineNumber, settings: _setting
66243
66564
  const current = widgets[selectedIndex];
66244
66565
  const customLabels = customKeybindsFor(current ? getWidgetImpl(current.type) : null, current).map((entry) => entry.label).join(", ");
66245
66566
  const normalHelp = "↑↓ select, ←→ change, Enter move, (a)dd, (i)nsert, (d)elete, (k)opy, (c)lear, Escape back";
66246
- return /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
66567
+ return /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
66247
66568
  flexDirection: "column",
66248
66569
  children: [
66249
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66570
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66250
66571
  bold: true,
66251
66572
  children: [
66252
66573
  `Edit Line ${lineNumber}`,
66253
- moveMode && /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66574
+ moveMode && /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66254
66575
  color: "blue",
66255
66576
  children: " [MOVE MODE]"
66256
66577
  }, undefined, false, undefined, this)
66257
66578
  ]
66258
66579
  }, undefined, true, undefined, this),
66259
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66580
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66260
66581
  dimColor: true,
66261
66582
  children: moveMode ? "↑↓ to move, Escape or Enter to finish" : customLabels ? `${normalHelp}, ${customLabels}` : normalHelp
66262
66583
  }, undefined, false, undefined, this),
66263
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
66584
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
66264
66585
  marginTop: 1,
66265
66586
  flexDirection: "column",
66266
- 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, {
66267
66588
  ...index === selectedIndex && { color: "green" },
66268
66589
  children: [
66269
66590
  index === selectedIndex ? "▶ " : " ",
66270
66591
  rowLabel(widget)
66271
66592
  ]
66272
- }, widget.id, true, undefined, this)) : /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
66593
+ }, widget.id, true, undefined, this)) : /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66273
66594
  dimColor: true,
66274
66595
  children: "No widgets yet. Press (a) to add one."
66275
66596
  }, undefined, false, undefined, this)
@@ -66328,17 +66649,17 @@ function cycleWidgetColor({ widgets, widgetId, direction, editingBackground, col
66328
66649
  }
66329
66650
 
66330
66651
  // src/tui/components/ColorMenu.tsx
66331
- var jsx_dev_runtime14 = __toESM(require_jsx_dev_runtime(), 1);
66652
+ var jsx_dev_runtime16 = __toESM(require_jsx_dev_runtime(), 1);
66332
66653
  function isTextInput(input2, key) {
66333
66654
  return Boolean(input2 && !key.ctrl && !key.meta && !key.tab);
66334
66655
  }
66335
66656
  function ColorMenu({ widgets, lineIndex, settings, onUpdate, onBack }) {
66336
- const [selectedIndex, setSelectedIndex] = import_react38.useState(0);
66337
- const [showSeparators, setShowSeparators] = import_react38.useState(false);
66338
- const [editingBackground, setEditingBackground] = import_react38.useState(false);
66339
- const [hexInput, setHexInput] = import_react38.useState(null);
66340
- const [ansiInput, setAnsiInput] = import_react38.useState(null);
66341
- 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);
66342
66663
  const colorable = widgets.filter((widget) => widget.type !== "separator" && widget.type !== "flex-separator" || showSeparators);
66343
66664
  const selected = colorable[selectedIndex];
66344
66665
  const colors = getAvailableColorsForUI().map((entry) => entry.value);
@@ -66402,14 +66723,14 @@ function ColorMenu({ widgets, lineIndex, settings, onUpdate, onBack }) {
66402
66723
  }
66403
66724
  });
66404
66725
  if (clearConfirm) {
66405
- return /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
66726
+ return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
66406
66727
  flexDirection: "column",
66407
66728
  children: [
66408
- /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66729
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66409
66730
  bold: true,
66410
66731
  children: "Clear all widget styling?"
66411
66732
  }, undefined, false, undefined, this),
66412
- /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(ConfirmDialog, {
66733
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(ConfirmDialog, {
66413
66734
  inline: true,
66414
66735
  onConfirm: () => {
66415
66736
  onUpdate(clearAllWidgetStyling(widgets));
@@ -66421,14 +66742,14 @@ function ColorMenu({ widgets, lineIndex, settings, onUpdate, onBack }) {
66421
66742
  }, undefined, true, undefined, this);
66422
66743
  }
66423
66744
  if (!colorable.length) {
66424
- return /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
66745
+ return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
66425
66746
  flexDirection: "column",
66426
66747
  children: [
66427
- /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66748
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66428
66749
  bold: true,
66429
66750
  children: `Colors — Line ${lineIndex + 1}`
66430
66751
  }, undefined, false, undefined, this),
66431
- /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66752
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66432
66753
  dimColor: true,
66433
66754
  children: "No colorable widgets. Press Escape to go back."
66434
66755
  }, undefined, false, undefined, this)
@@ -66436,38 +66757,38 @@ function ColorMenu({ widgets, lineIndex, settings, onUpdate, onBack }) {
66436
66757
  }, undefined, true, undefined, this);
66437
66758
  }
66438
66759
  const inputMode = hexInput !== null ? `Hex: #${hexInput}` : ansiInput !== null ? `ANSI 256: ${ansiInput}` : null;
66439
- return /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
66760
+ return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
66440
66761
  flexDirection: "column",
66441
66762
  children: [
66442
- /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66763
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66443
66764
  bold: true,
66444
66765
  children: [
66445
66766
  `Colors — Line ${lineIndex + 1}`,
66446
- editingBackground && /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66767
+ editingBackground && /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66447
66768
  color: "yellow",
66448
66769
  children: " [Background]"
66449
66770
  }, undefined, false, undefined, this)
66450
66771
  ]
66451
66772
  }, undefined, true, undefined, this),
66452
- inputMode ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66773
+ inputMode ? /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66453
66774
  children: [
66454
66775
  inputMode,
66455
- /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66776
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66456
66777
  dimColor: true,
66457
66778
  children: " Enter to apply, Escape to cancel"
66458
66779
  }, undefined, false, undefined, this)
66459
66780
  ]
66460
- }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66781
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66461
66782
  dimColor: true,
66462
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`
66463
66784
  }, undefined, false, undefined, this),
66464
- /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
66785
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
66465
66786
  marginTop: 1,
66466
66787
  flexDirection: "column",
66467
66788
  children: colorable.map((widget, index) => {
66468
66789
  const label = displayWidgetType(widget.type);
66469
66790
  const styled = applyColors(label, widget.color, widget.backgroundColor, widget.bold, getColorLevelString(settings.colorLevel), widget.dim);
66470
- return /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66791
+ return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66471
66792
  ...index === selectedIndex && { color: "green" },
66472
66793
  children: [
66473
66794
  index === selectedIndex ? "▶ " : " ",
@@ -66476,7 +66797,7 @@ function ColorMenu({ widgets, lineIndex, settings, onUpdate, onBack }) {
66476
66797
  }, widget.id, true, undefined, this);
66477
66798
  })
66478
66799
  }, undefined, false, undefined, this),
66479
- !settings.powerline.enabled && !settings.defaultSeparator && /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
66800
+ !settings.powerline.enabled && !settings.defaultSeparator && /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
66480
66801
  dimColor: true,
66481
66802
  children: `(s)how separators: ${showSeparators ? "ON" : "OFF"}`
66482
66803
  }, undefined, false, undefined, this)
@@ -66485,13 +66806,13 @@ function ColorMenu({ widgets, lineIndex, settings, onUpdate, onBack }) {
66485
66806
  }
66486
66807
 
66487
66808
  // src/tui/components/ExportConfigDialog.tsx
66488
- var import_react39 = __toESM(require_react(), 1);
66489
- 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);
66490
66811
  function acceptsText(input2, key) {
66491
66812
  return Boolean(input2 && !key.ctrl && !key.meta && !key.tab);
66492
66813
  }
66493
66814
  function ExportConfigDialog({ initialPath, onExport, onCancel }) {
66494
- const [path, setPath] = import_react39.useState(initialPath);
66815
+ const [path, setPath] = import_react45.useState(initialPath);
66495
66816
  use_input_default((input2, key) => {
66496
66817
  if (key.return)
66497
66818
  onExport(path);
@@ -66502,27 +66823,27 @@ function ExportConfigDialog({ initialPath, onExport, onCancel }) {
66502
66823
  else if (acceptsText(input2, key))
66503
66824
  setPath((current) => current + input2);
66504
66825
  });
66505
- return /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
66826
+ return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
66506
66827
  flexDirection: "column",
66507
66828
  children: [
66508
- /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66829
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
66509
66830
  bold: true,
66510
66831
  children: "Export Config"
66511
66832
  }, undefined, false, undefined, this),
66512
- /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66833
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
66513
66834
  dimColor: true,
66514
66835
  children: "Enter the file path to export your configuration to:"
66515
66836
  }, undefined, false, undefined, this),
66516
- /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66837
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
66517
66838
  children: [
66518
66839
  `Path: ${path}`,
66519
- /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66840
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
66520
66841
  inverse: true,
66521
66842
  children: " "
66522
66843
  }, undefined, false, undefined, this)
66523
66844
  ]
66524
66845
  }, undefined, true, undefined, this),
66525
- /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
66846
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
66526
66847
  dimColor: true,
66527
66848
  children: "Enter to confirm, Escape to cancel"
66528
66849
  }, undefined, false, undefined, this)
@@ -66531,8 +66852,8 @@ function ExportConfigDialog({ initialPath, onExport, onCancel }) {
66531
66852
  }
66532
66853
 
66533
66854
  // src/tui/components/GlobalOverridesMenu.tsx
66534
- var import_react40 = __toESM(require_react(), 1);
66535
- 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);
66536
66857
  function acceptsText2(input2, key) {
66537
66858
  return Boolean(input2 && !key.ctrl && !key.meta && !key.tab);
66538
66859
  }
@@ -66557,16 +66878,16 @@ function cycleGlobalNumberStyle(settings, kind) {
66557
66878
  };
66558
66879
  }
66559
66880
  function GlobalOverridesMenu({ settings, onUpdate, onBack }) {
66560
- const [editing, setEditing] = import_react40.useState(null);
66561
- const [value, setValue] = import_react40.useState("");
66562
- const [confirmSeparator, setConfirmSeparator] = import_react40.useState(false);
66563
- const [numberFormatMode, setNumberFormatMode] = import_react40.useState(false);
66564
- const [numberFormatKindIndex, setNumberFormatKindIndex] = import_react40.useState(0);
66565
- const [gradientMode, setGradientMode] = import_react40.useState(false);
66566
- const [gradientIndex, setGradientIndex] = import_react40.useState(0);
66567
- const [gradientStep, setGradientStep] = import_react40.useState(null);
66568
- const [gradientStart, setGradientStart] = import_react40.useState("");
66569
- 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("");
66570
66891
  const foregrounds = getAvailableColorsForUI().map((entry) => entry.value);
66571
66892
  const backgrounds = getAvailableBackgroundColorsForUI().map((entry) => entry.value);
66572
66893
  const powerline = settings.powerline.enabled;
@@ -66695,14 +67016,14 @@ function GlobalOverridesMenu({ settings, onUpdate, onBack }) {
66695
67016
  }
66696
67017
  });
66697
67018
  if (confirmSeparator) {
66698
- return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
67019
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
66699
67020
  flexDirection: "column",
66700
67021
  children: [
66701
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67022
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66702
67023
  color: "yellow",
66703
67024
  children: "Setting a default separator removes manual separators. Continue?"
66704
67025
  }, undefined, false, undefined, this),
66705
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(ConfirmDialog, {
67026
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(ConfirmDialog, {
66706
67027
  inline: true,
66707
67028
  onConfirm: () => {
66708
67029
  onUpdate({ ...settings, defaultSeparator: value, lines: settings.lines.map((line3) => line3.filter((item) => item.type !== "separator")) });
@@ -66719,30 +67040,30 @@ function GlobalOverridesMenu({ settings, onUpdate, onBack }) {
66719
67040
  }
66720
67041
  if (gradientMode) {
66721
67042
  if (gradientStep) {
66722
- return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
67043
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
66723
67044
  flexDirection: "column",
66724
67045
  children: [
66725
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67046
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66726
67047
  bold: true,
66727
67048
  children: "Custom Gradient — Override FG Color"
66728
67049
  }, undefined, false, undefined, this),
66729
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67050
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66730
67051
  children: gradientStep === "start" ? "Enter START hex color:" : "Enter END hex color:"
66731
67052
  }, undefined, false, undefined, this),
66732
- gradientStep === "end" && /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67053
+ gradientStep === "end" && /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66733
67054
  dimColor: true,
66734
67055
  children: `Start: #${gradientStart}`
66735
67056
  }, undefined, false, undefined, this),
66736
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67057
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66737
67058
  children: [
66738
67059
  `#${gradientInput}`,
66739
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67060
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66740
67061
  dimColor: true,
66741
67062
  children: "_".repeat(6 - gradientInput.length)
66742
67063
  }, undefined, false, undefined, this)
66743
67064
  ]
66744
67065
  }, undefined, true, undefined, this),
66745
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67066
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66746
67067
  dimColor: true,
66747
67068
  children: "Enter to continue, Escape to go back"
66748
67069
  }, undefined, false, undefined, this)
@@ -66750,28 +67071,28 @@ function GlobalOverridesMenu({ settings, onUpdate, onBack }) {
66750
67071
  }, undefined, true, undefined, this);
66751
67072
  }
66752
67073
  const level = getColorLevelString(settings.colorLevel);
66753
- return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
67074
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
66754
67075
  flexDirection: "column",
66755
67076
  children: [
66756
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67077
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66757
67078
  bold: true,
66758
67079
  children: "Select Gradient — Override FG Color"
66759
67080
  }, undefined, false, undefined, this),
66760
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67081
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66761
67082
  dimColor: true,
66762
67083
  children: "↑↓ select, Enter apply, Escape cancel"
66763
67084
  }, undefined, false, undefined, this),
66764
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
67085
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
66765
67086
  marginTop: 1,
66766
67087
  flexDirection: "column",
66767
67088
  children: [
66768
- 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, {
66769
67090
  children: [
66770
67091
  index === gradientIndex ? "▶ " : " ",
66771
67092
  applyColors(name, `gradient:${name}`, undefined, index === gradientIndex, level)
66772
67093
  ]
66773
67094
  }, name, true, undefined, this)),
66774
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67095
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66775
67096
  children: [
66776
67097
  gradientIndex === GRADIENT_PRESET_NAMES.length ? "▶ " : " ",
66777
67098
  "Custom (two hex stops)"
@@ -66784,23 +67105,23 @@ function GlobalOverridesMenu({ settings, onUpdate, onBack }) {
66784
67105
  }
66785
67106
  if (numberFormatMode) {
66786
67107
  const width = Math.max(...NUMBER_KINDS.map((kind) => kind.length));
66787
- return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
67108
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
66788
67109
  flexDirection: "column",
66789
67110
  children: [
66790
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67111
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66791
67112
  bold: true,
66792
67113
  children: "Global Number Formatting"
66793
67114
  }, undefined, false, undefined, this),
66794
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67115
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66795
67116
  dimColor: true,
66796
67117
  children: "↑↓ to select a number type, ←→ to cycle its style, ESC to go back"
66797
67118
  }, undefined, false, undefined, this),
66798
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
67119
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
66799
67120
  marginTop: 1,
66800
67121
  flexDirection: "column",
66801
67122
  children: NUMBER_KINDS.map((kind, idx) => {
66802
67123
  const style = settings.numberFormat?.[kind]?.style ?? "precise (default)";
66803
- return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67124
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66804
67125
  ...idx === numberFormatKindIndex && { color: "cyan" },
66805
67126
  children: [
66806
67127
  idx === numberFormatKindIndex ? "▶ " : " ",
@@ -66811,15 +67132,15 @@ function GlobalOverridesMenu({ settings, onUpdate, onBack }) {
66811
67132
  }, kind, true, undefined, this);
66812
67133
  })
66813
67134
  }, undefined, false, undefined, this),
66814
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
67135
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
66815
67136
  marginTop: 1,
66816
67137
  flexDirection: "column",
66817
67138
  children: [
66818
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67139
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66819
67140
  dimColor: true,
66820
67141
  children: "precise = keep trailing zeros (1.0M), compact = trim them (1M / 1.1M), whole = no decimals (1M)."
66821
67142
  }, undefined, false, undefined, this),
66822
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67143
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66823
67144
  dimColor: true,
66824
67145
  children: "A global style forces that type across every widget. Decimal places are set per-widget or in settings.json."
66825
67146
  }, undefined, false, undefined, this)
@@ -66829,68 +67150,68 @@ function GlobalOverridesMenu({ settings, onUpdate, onBack }) {
66829
67150
  }, undefined, true, undefined, this);
66830
67151
  }
66831
67152
  if (editing) {
66832
- return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
67153
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
66833
67154
  flexDirection: "column",
66834
67155
  children: [
66835
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67156
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66836
67157
  bold: true,
66837
67158
  children: editing === "padding" ? "Default Padding" : "Default Separator"
66838
67159
  }, undefined, false, undefined, this),
66839
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67160
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66840
67161
  children: [
66841
67162
  value,
66842
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67163
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66843
67164
  inverse: true,
66844
67165
  children: " "
66845
67166
  }, undefined, false, undefined, this)
66846
67167
  ]
66847
67168
  }, undefined, true, undefined, this),
66848
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67169
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66849
67170
  dimColor: true,
66850
67171
  children: "Enter to apply, Escape to cancel"
66851
67172
  }, undefined, false, undefined, this)
66852
67173
  ]
66853
67174
  }, undefined, true, undefined, this);
66854
67175
  }
66855
- return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
67176
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
66856
67177
  flexDirection: "column",
66857
67178
  children: [
66858
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67179
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66859
67180
  bold: true,
66860
67181
  children: "Global Overrides"
66861
67182
  }, undefined, false, undefined, this),
66862
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67183
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66863
67184
  dimColor: true,
66864
67185
  children: "Configure rendering-wide padding, separators, and styling."
66865
67186
  }, undefined, false, undefined, this),
66866
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67187
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66867
67188
  children: `Global Bold: ${settings.globalBold ? "Enabled" : "Disabled"} (o)`
66868
67189
  }, undefined, false, undefined, this),
66869
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67190
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66870
67191
  children: `Minimalist Mode: ${settings.minimalistMode ? "Enabled" : "Disabled"} (m)`
66871
67192
  }, undefined, false, undefined, this),
66872
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67193
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66873
67194
  children: `Number Formatting: ${settings.numberFormat ? "customized" : "(defaults)"} (n)`
66874
67195
  }, undefined, false, undefined, this),
66875
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67196
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66876
67197
  children: `Default Padding: ${settings.defaultPadding ? JSON.stringify(settings.defaultPadding) : "none"} (p)`
66877
67198
  }, undefined, false, undefined, this),
66878
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67199
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66879
67200
  children: `Padding Side: ${settings.defaultPaddingSide} (d)`
66880
67201
  }, undefined, false, undefined, this),
66881
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67202
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66882
67203
  children: `Override FG: ${settings.overrideForegroundColor ?? "none"} (f cycle, g gradient, x clear)`
66883
67204
  }, undefined, false, undefined, this),
66884
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67205
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66885
67206
  children: powerline ? "Override BG: disabled while Powerline is active" : `Override BG: ${settings.overrideBackgroundColor ?? "none"} (b cycle, c clear)`
66886
67207
  }, undefined, false, undefined, this),
66887
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67208
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66888
67209
  children: powerline ? "Default Separator: disabled while Powerline is active" : `Default Separator: ${settings.defaultSeparator ? JSON.stringify(settings.defaultSeparator) : "none"} (s)`
66889
67210
  }, undefined, false, undefined, this),
66890
- !powerline && /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67211
+ !powerline && /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66891
67212
  children: `Inherit Separator Colors: ${settings.inheritSeparatorColors ? "Enabled" : "Disabled"} (i)`
66892
67213
  }, undefined, false, undefined, this),
66893
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
67214
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
66894
67215
  dimColor: true,
66895
67216
  children: "Escape to cancel these changes"
66896
67217
  }, undefined, false, undefined, this)
@@ -66899,13 +67220,13 @@ function GlobalOverridesMenu({ settings, onUpdate, onBack }) {
66899
67220
  }
66900
67221
 
66901
67222
  // src/tui/components/ImportConfigDialog.tsx
66902
- var import_react41 = __toESM(require_react(), 1);
66903
- 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);
66904
67225
  function acceptsText3(input2, key) {
66905
67226
  return Boolean(input2 && !key.ctrl && !key.meta && !key.tab);
66906
67227
  }
66907
67228
  function ImportConfigDialog({ error: error61, onFileChosen, onCancel }) {
66908
- const [path, setPath] = import_react41.useState("");
67229
+ const [path, setPath] = import_react47.useState("");
66909
67230
  use_input_default((input2, key) => {
66910
67231
  if (key.return)
66911
67232
  onFileChosen(path);
@@ -66916,31 +67237,31 @@ function ImportConfigDialog({ error: error61, onFileChosen, onCancel }) {
66916
67237
  else if (acceptsText3(input2, key))
66917
67238
  setPath((current) => current + input2);
66918
67239
  });
66919
- return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
67240
+ return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
66920
67241
  flexDirection: "column",
66921
67242
  children: [
66922
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
67243
+ /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
66923
67244
  bold: true,
66924
67245
  children: "Import Config"
66925
67246
  }, undefined, false, undefined, this),
66926
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
67247
+ /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
66927
67248
  dimColor: true,
66928
67249
  children: "Enter the file path to import configuration from:"
66929
67250
  }, undefined, false, undefined, this),
66930
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
67251
+ /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
66931
67252
  children: [
66932
67253
  `Path: ${path}`,
66933
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
67254
+ /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
66934
67255
  inverse: true,
66935
67256
  children: " "
66936
67257
  }, undefined, false, undefined, this)
66937
67258
  ]
66938
67259
  }, undefined, true, undefined, this),
66939
- error61 && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
67260
+ error61 && /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
66940
67261
  color: "red",
66941
67262
  children: error61
66942
67263
  }, undefined, false, undefined, this),
66943
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
67264
+ /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
66944
67265
  dimColor: true,
66945
67266
  children: "Enter to preview, Escape to cancel"
66946
67267
  }, undefined, false, undefined, this)
@@ -66949,7 +67270,7 @@ function ImportConfigDialog({ error: error61, onFileChosen, onCancel }) {
66949
67270
  }
66950
67271
 
66951
67272
  // src/tui/components/StatusLinePreview.tsx
66952
- var jsx_dev_runtime18 = __toESM(require_jsx_dev_runtime(), 1);
67273
+ var jsx_dev_runtime20 = __toESM(require_jsx_dev_runtime(), 1);
66953
67274
  var PREVIEW_CONTEXT = {
66954
67275
  data: { payload_version: 1 },
66955
67276
  now: new Date(0),
@@ -66957,78 +67278,78 @@ var PREVIEW_CONTEXT = {
66957
67278
  };
66958
67279
  function StatusLinePreview({ settings, terminalWidth }) {
66959
67280
  const rows = renderStatusLines(settings, { ...PREVIEW_CONTEXT, isPreview: true, terminalWidth });
66960
- return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
67281
+ return /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
66961
67282
  flexDirection: "column",
66962
- children: rows.map((row, i) => /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
67283
+ children: rows.map((row, i) => /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
66963
67284
  children: row
66964
67285
  }, i, false, undefined, this))
66965
67286
  }, undefined, false, undefined, this);
66966
67287
  }
66967
67288
 
66968
67289
  // src/tui/components/ImportPreviewDialog.tsx
66969
- var jsx_dev_runtime19 = __toESM(require_jsx_dev_runtime(), 1);
67290
+ var jsx_dev_runtime21 = __toESM(require_jsx_dev_runtime(), 1);
66970
67291
  function ImportPreviewDialog({ preview, terminalWidth, busy = false, onConfirm, onCancel }) {
66971
67292
  const rows = renderStatusLines(preview.settings, { ...PREVIEW_CONTEXT, isPreview: true, terminalWidth });
66972
67293
  const allCustomCommands = preview.settings.lines.flat().filter((item) => item.type === "custom-command");
66973
67294
  const uncachedCommands = allCustomCommands.filter((item) => item.refreshMs === undefined).map((item) => item.commandPath ?? "(no command)");
66974
67295
  const cachedCommands = allCustomCommands.filter((item) => item.refreshMs !== undefined).map((item) => `${item.commandPath ?? "(no command)"} (every ${item.refreshMs}ms)`);
66975
- return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
67296
+ return /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Box_default, {
66976
67297
  flexDirection: "column",
66977
67298
  children: [
66978
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67299
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
66979
67300
  bold: true,
66980
67301
  children: "Import Preview"
66981
67302
  }, undefined, false, undefined, this),
66982
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67303
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
66983
67304
  dimColor: true,
66984
67305
  children: "Preview rendered by the production statusline renderer:"
66985
67306
  }, undefined, false, undefined, this),
66986
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
67307
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Box_default, {
66987
67308
  marginTop: 1,
66988
67309
  flexDirection: "column",
66989
- children: rows.map((row, index) => /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67310
+ children: rows.map((row, index) => /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
66990
67311
  children: row
66991
67312
  }, index, false, undefined, this))
66992
67313
  }, undefined, false, undefined, this),
66993
- preview.omittedTypes.length > 0 && /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67314
+ preview.omittedTypes.length > 0 && /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
66994
67315
  color: "yellow",
66995
67316
  children: `Deferred unsupported widgets: ${preview.omittedTypes.join(", ")}`
66996
67317
  }, undefined, false, undefined, this),
66997
- uncachedCommands.length > 0 && /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
67318
+ uncachedCommands.length > 0 && /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Box_default, {
66998
67319
  flexDirection: "column",
66999
67320
  children: [
67000
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67321
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
67001
67322
  color: "yellow",
67002
67323
  children: "Commands that will run on every render:"
67003
67324
  }, undefined, false, undefined, this),
67004
- uncachedCommands.map((command, index) => /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67325
+ uncachedCommands.map((command, index) => /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
67005
67326
  color: "yellow",
67006
67327
  children: ` ${command}`
67007
67328
  }, index, false, undefined, this))
67008
67329
  ]
67009
67330
  }, undefined, true, undefined, this),
67010
- cachedCommands.length > 0 && /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
67331
+ cachedCommands.length > 0 && /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Box_default, {
67011
67332
  flexDirection: "column",
67012
67333
  children: [
67013
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67334
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
67014
67335
  color: "yellow",
67015
67336
  children: "Cached commands (run in background):"
67016
67337
  }, undefined, false, undefined, this),
67017
- cachedCommands.map((command, index) => /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67338
+ cachedCommands.map((command, index) => /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
67018
67339
  color: "yellow",
67019
67340
  children: ` ${command}`
67020
67341
  }, index, false, undefined, this))
67021
67342
  ]
67022
67343
  }, undefined, true, undefined, this),
67023
- busy ? /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67344
+ busy ? /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
67024
67345
  dimColor: true,
67025
67346
  children: "Applying imported configuration…"
67026
- }, 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, {
67027
67348
  children: [
67028
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
67349
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
67029
67350
  children: "Apply this preset?"
67030
67351
  }, undefined, false, undefined, this),
67031
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(ConfirmDialog, {
67352
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(ConfirmDialog, {
67032
67353
  inline: true,
67033
67354
  onConfirm,
67034
67355
  onCancel
@@ -67040,8 +67361,8 @@ function ImportPreviewDialog({ preview, terminalWidth, busy = false, onConfirm,
67040
67361
  }
67041
67362
 
67042
67363
  // src/tui/components/LineSelector.tsx
67043
- var import_react42 = __toESM(require_react(), 1);
67044
- 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);
67045
67366
  function cloneLines(lines) {
67046
67367
  return lines.map((line3) => line3.map((item) => ({ ...item, ...item.metadata && { metadata: { ...item.metadata } } })));
67047
67368
  }
@@ -67057,12 +67378,12 @@ function LineSelector({
67057
67378
  title = "Edit Lines",
67058
67379
  allowEditing = false
67059
67380
  }) {
67060
- const [selectedIndex, setSelectedIndex] = import_react42.useState(initialSelection);
67061
- const [localLines, setLocalLines] = import_react42.useState(() => cloneLines(lines));
67062
- const [moveMode, setMoveMode] = import_react42.useState(false);
67063
- const [confirmDelete, setConfirmDelete] = import_react42.useState(false);
67064
- const [limitMessage, setLimitMessage] = import_react42.useState(null);
67065
- 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(() => {
67066
67387
  setLocalLines(cloneLines(lines));
67067
67388
  setSelectedIndex((current) => Math.min(current, Math.max(0, lines.length - 1)));
67068
67389
  }, [lines]);
@@ -67114,18 +67435,18 @@ function LineSelector({
67114
67435
  onBack();
67115
67436
  });
67116
67437
  if (confirmDelete) {
67117
- return /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
67438
+ return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
67118
67439
  flexDirection: "column",
67119
67440
  children: [
67120
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
67441
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67121
67442
  bold: true,
67122
67443
  children: `Delete Line ${selectedIndex + 1}?`
67123
67444
  }, undefined, false, undefined, this),
67124
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
67445
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67125
67446
  dimColor: true,
67126
67447
  children: lineSummary(localLines[selectedIndex] ?? [])
67127
67448
  }, undefined, false, undefined, this),
67128
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(ConfirmDialog, {
67449
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(ConfirmDialog, {
67129
67450
  inline: true,
67130
67451
  onConfirm: () => {
67131
67452
  const next = localLines.filter((_2, index) => index !== selectedIndex);
@@ -67139,28 +67460,28 @@ function LineSelector({
67139
67460
  }, undefined, true, undefined, this);
67140
67461
  }
67141
67462
  if (moveMode) {
67142
- return /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
67463
+ return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
67143
67464
  flexDirection: "column",
67144
67465
  children: [
67145
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
67466
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67146
67467
  bold: true,
67147
67468
  children: [
67148
67469
  title,
67149
67470
  " ",
67150
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
67471
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67151
67472
  color: "blue",
67152
67473
  children: "[MOVE MODE]"
67153
67474
  }, undefined, false, undefined, this)
67154
67475
  ]
67155
67476
  }, undefined, true, undefined, this),
67156
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
67477
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67157
67478
  dimColor: true,
67158
67479
  children: "↑↓ to move a line, Escape or Enter to finish"
67159
67480
  }, undefined, false, undefined, this),
67160
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
67481
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
67161
67482
  marginTop: 1,
67162
67483
  flexDirection: "column",
67163
- children: localLines.map((line3, index) => /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
67484
+ children: localLines.map((line3, index) => /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67164
67485
  ...index === selectedIndex && { color: "green" },
67165
67486
  children: [
67166
67487
  index === selectedIndex ? "◆ " : " ",
@@ -67171,22 +67492,22 @@ function LineSelector({
67171
67492
  ]
67172
67493
  }, undefined, true, undefined, this);
67173
67494
  }
67174
- return /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
67495
+ return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
67175
67496
  flexDirection: "column",
67176
67497
  children: [
67177
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
67498
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67178
67499
  bold: true,
67179
67500
  children: title
67180
67501
  }, undefined, false, undefined, this),
67181
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
67502
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67182
67503
  dimColor: true,
67183
67504
  children: allowEditing ? "Enter to edit; (a)dd, (d)elete, (m)ove; Escape to cancel" : "Enter to choose a line; Escape to cancel"
67184
67505
  }, undefined, false, undefined, this),
67185
- limitMessage && /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
67506
+ limitMessage && /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67186
67507
  color: "yellow",
67187
67508
  children: limitMessage
67188
67509
  }, undefined, false, undefined, this),
67189
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(List, {
67510
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(List, {
67190
67511
  marginTop: 1,
67191
67512
  items: localLines.map((line3, index) => ({ label: `Line ${index + 1}`, sublabel: `(${lineSummary(line3)})`, value: index })),
67192
67513
  initialSelection: selectedIndex,
@@ -67199,7 +67520,7 @@ function LineSelector({
67199
67520
  }
67200
67521
 
67201
67522
  // src/tui/components/MainMenu.tsx
67202
- var jsx_dev_runtime21 = __toESM(require_jsx_dev_runtime(), 1);
67523
+ var jsx_dev_runtime23 = __toESM(require_jsx_dev_runtime(), 1);
67203
67524
  function buildMainMenuItems() {
67204
67525
  return [
67205
67526
  { label: "Lines", value: "lines", description: "Edit up to three status-line rows and their widgets." },
@@ -67215,17 +67536,17 @@ function buildMainMenuItems() {
67215
67536
  ];
67216
67537
  }
67217
67538
  function MainMenu({ onSelect, initialSelection = 0, hasChanges = false }) {
67218
- return /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Box_default, {
67539
+ return /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Box_default, {
67219
67540
  flexDirection: "column",
67220
67541
  children: [
67221
- /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Text, {
67542
+ /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text, {
67222
67543
  bold: true,
67223
67544
  children: [
67224
67545
  "Main Menu",
67225
67546
  hasChanges ? " (unsaved changes)" : ""
67226
67547
  ]
67227
67548
  }, undefined, true, undefined, this),
67228
- /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(List, {
67549
+ /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(List, {
67229
67550
  items: buildMainMenuItems(),
67230
67551
  marginTop: 1,
67231
67552
  initialSelection,
@@ -67241,8 +67562,8 @@ function MainMenu({ onSelect, initialSelection = 0, hasChanges = false }) {
67241
67562
  // src/tui/components/PowerlineSetup.tsx
67242
67563
  import { existsSync as existsSync16, readdirSync as readdirSync5 } from "node:fs";
67243
67564
  import { homedir as homedir2, platform as platform2 } from "node:os";
67244
- import { join as join23 } from "node:path";
67245
- var import_react45 = __toESM(require_react(), 1);
67565
+ import { join as join22 } from "node:path";
67566
+ var import_react51 = __toESM(require_react(), 1);
67246
67567
 
67247
67568
  // src/utils/powerline-settings.ts
67248
67569
  function resolveEnabledPowerlineTheme(theme) {
@@ -67269,8 +67590,8 @@ function buildEnabledPowerlineSettings(settings, removeManualSeparators) {
67269
67590
  }
67270
67591
 
67271
67592
  // src/tui/components/PowerlineSeparatorEditor.tsx
67272
- var import_react43 = __toESM(require_react(), 1);
67273
- 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);
67274
67595
  var PRESETS = {
67275
67596
  separator: [
67276
67597
  { char: "", name: "Triangle Right" },
@@ -67309,8 +67630,8 @@ function PowerlineSeparatorEditor({ settings, mode, onUpdate, onBack }) {
67309
67630
  const items = itemsFor(settings, mode);
67310
67631
  const presets = PRESETS[mode];
67311
67632
  const inversions = mode === "separator" ? settings.powerline.separatorInvertBackground : [];
67312
- const [selectedIndex, setSelectedIndex] = import_react43.useState(0);
67313
- const [hexInput, setHexInput] = import_react43.useState(null);
67633
+ const [selectedIndex, setSelectedIndex] = import_react49.useState(0);
67634
+ const [hexInput, setHexInput] = import_react49.useState(null);
67314
67635
  const update2 = (nextItems, nextInversions = inversions) => {
67315
67636
  const powerline = mode === "separator" ? { ...settings.powerline, separators: nextItems, separatorInvertBackground: nextInversions } : mode === "startCap" ? { ...settings.powerline, startCaps: nextItems } : { ...settings.powerline, endCaps: nextItems };
67316
67637
  onUpdate({ ...settings, powerline });
@@ -67380,55 +67701,55 @@ function PowerlineSeparatorEditor({ settings, mode, onUpdate, onBack }) {
67380
67701
  }
67381
67702
  });
67382
67703
  if (hexInput !== null) {
67383
- return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
67704
+ return /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Box_default, {
67384
67705
  flexDirection: "column",
67385
67706
  children: [
67386
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67707
+ /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
67387
67708
  bold: true,
67388
67709
  children: titleFor(mode)
67389
67710
  }, undefined, false, undefined, this),
67390
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67711
+ /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
67391
67712
  children: [
67392
67713
  `U+${hexInput}`,
67393
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67714
+ /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
67394
67715
  inverse: true,
67395
67716
  children: " "
67396
67717
  }, undefined, false, undefined, this)
67397
67718
  ]
67398
67719
  }, undefined, true, undefined, this),
67399
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67720
+ /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
67400
67721
  dimColor: true,
67401
67722
  children: "Enter 4–6 hexadecimal digits, Escape to cancel"
67402
67723
  }, undefined, false, undefined, this)
67403
67724
  ]
67404
67725
  }, undefined, true, undefined, this);
67405
67726
  }
67406
- return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
67727
+ return /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Box_default, {
67407
67728
  flexDirection: "column",
67408
67729
  children: [
67409
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67730
+ /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
67410
67731
  bold: true,
67411
67732
  children: titleFor(mode)
67412
67733
  }, undefined, false, undefined, this),
67413
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67734
+ /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
67414
67735
  dimColor: true,
67415
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`
67416
67737
  }, undefined, false, undefined, this),
67417
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
67738
+ /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Box_default, {
67418
67739
  marginTop: 1,
67419
67740
  flexDirection: "column",
67420
67741
  children: items.length ? items.map((item, index) => {
67421
67742
  const preset = presets.find((entry) => entry.char === item);
67422
67743
  const code = item.codePointAt(0)?.toString(16).toUpperCase().padStart(4, "0");
67423
67744
  const label = preset ? `${item} - ${preset.name}` : `${item} - Custom (U+${code})`;
67424
- return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67745
+ return /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
67425
67746
  ...index === selected && { color: "green" },
67426
67747
  children: [
67427
67748
  index === selected ? "▶ " : " ",
67428
67749
  `${index + 1}: ${label}${mode === "separator" && inversions[index] ? " [Inverted]" : ""}`
67429
67750
  ]
67430
67751
  }, `${item}-${index}`, true, undefined, this);
67431
- }) : /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
67752
+ }) : /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
67432
67753
  dimColor: true,
67433
67754
  children: "(none configured — press a to add)"
67434
67755
  }, undefined, false, undefined, this)
@@ -67438,8 +67759,8 @@ function PowerlineSeparatorEditor({ settings, mode, onUpdate, onBack }) {
67438
67759
  }
67439
67760
 
67440
67761
  // src/tui/components/PowerlineThemeSelector.tsx
67441
- var import_react44 = __toESM(require_react(), 1);
67442
- 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);
67443
67764
  function buildPowerlineThemeItems(themes, originalTheme) {
67444
67765
  return themes.map((themeName) => {
67445
67766
  const theme = getPowerlineTheme(themeName);
@@ -67478,17 +67799,17 @@ function applyCustomPowerlineTheme(settings, themeName) {
67478
67799
  };
67479
67800
  }
67480
67801
  function PowerlineThemeSelector({ settings, onUpdate, onBack }) {
67481
- const themes = import_react44.useMemo(() => getPowerlineThemes(), []);
67482
- const originalSettings = import_react44.useRef(settings);
67483
- const originalTheme = import_react44.useRef(settings.powerline.theme ?? "custom");
67484
- const [selectedIndex, setSelectedIndex] = import_react44.useState(Math.max(0, themes.indexOf(originalTheme.current)));
67485
- const [confirmCustom, setConfirmCustom] = import_react44.useState(false);
67486
- const latest = import_react44.useRef({ settings, onUpdate });
67487
- const initialized = import_react44.useRef(false);
67488
- 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(() => {
67489
67810
  latest.current = { settings, onUpdate };
67490
67811
  }, [settings, onUpdate]);
67491
- import_react44.useEffect(() => {
67812
+ import_react50.useEffect(() => {
67492
67813
  const theme = themes[selectedIndex];
67493
67814
  if (!theme || !initialized.current) {
67494
67815
  initialized.current = true;
@@ -67510,21 +67831,21 @@ function PowerlineThemeSelector({ settings, onUpdate, onBack }) {
67510
67831
  });
67511
67832
  const selectedTheme = themes[selectedIndex];
67512
67833
  if (confirmCustom) {
67513
- return /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Box_default, {
67834
+ return /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Box_default, {
67514
67835
  flexDirection: "column",
67515
67836
  children: [
67516
- /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text, {
67837
+ /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
67517
67838
  bold: true,
67518
67839
  color: "yellow",
67519
67840
  children: "Confirm Customization"
67520
67841
  }, undefined, false, undefined, this),
67521
- /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text, {
67842
+ /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
67522
67843
  children: "This copies the current theme colors to widgets and overwrites existing widget colors."
67523
67844
  }, undefined, false, undefined, this),
67524
- /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text, {
67845
+ /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
67525
67846
  children: "Continue?"
67526
67847
  }, undefined, false, undefined, this),
67527
- /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(ConfirmDialog, {
67848
+ /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(ConfirmDialog, {
67528
67849
  inline: true,
67529
67850
  onConfirm: () => {
67530
67851
  if (selectedTheme) {
@@ -67540,24 +67861,24 @@ function PowerlineThemeSelector({ settings, onUpdate, onBack }) {
67540
67861
  ]
67541
67862
  }, undefined, true, undefined, this);
67542
67863
  }
67543
- return /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Box_default, {
67864
+ return /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Box_default, {
67544
67865
  flexDirection: "column",
67545
67866
  children: [
67546
- /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text, {
67867
+ /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
67547
67868
  bold: true,
67548
67869
  children: [
67549
67870
  "Powerline Theme Selection ",
67550
- /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text, {
67871
+ /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
67551
67872
  dimColor: true,
67552
67873
  children: `| Original: ${originalTheme.current}`
67553
67874
  }, undefined, false, undefined, this)
67554
67875
  ]
67555
67876
  }, undefined, true, undefined, this),
67556
- /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text, {
67877
+ /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
67557
67878
  dimColor: true,
67558
67879
  children: `↑↓ navigate, Enter apply${selectedTheme && selectedTheme !== "custom" ? ", (c)ustomize theme" : ""}, Escape cancel`
67559
67880
  }, undefined, false, undefined, this),
67560
- /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(List, {
67881
+ /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(List, {
67561
67882
  marginTop: 1,
67562
67883
  items: buildPowerlineThemeItems(themes, originalTheme.current),
67563
67884
  initialSelection: selectedIndex,
@@ -67567,7 +67888,7 @@ function PowerlineThemeSelector({ settings, onUpdate, onBack }) {
67567
67888
  },
67568
67889
  onSelect: () => onBack()
67569
67890
  }, undefined, false, undefined, this),
67570
- settings.colorLevel === 1 && /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(Text, {
67891
+ settings.colorLevel === 1 && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
67571
67892
  color: "yellow",
67572
67893
  children: "16-color themes have a limited palette."
67573
67894
  }, undefined, false, undefined, this)
@@ -67576,7 +67897,7 @@ function PowerlineThemeSelector({ settings, onUpdate, onBack }) {
67576
67897
  }
67577
67898
 
67578
67899
  // src/tui/components/PowerlineSetup.tsx
67579
- var jsx_dev_runtime24 = __toESM(require_jsx_dev_runtime(), 1);
67900
+ var jsx_dev_runtime26 = __toESM(require_jsx_dev_runtime(), 1);
67580
67901
  var SEPARATORS = [
67581
67902
  { char: "", name: "Triangle Right" },
67582
67903
  { char: "", name: "Triangle Left" },
@@ -67626,7 +67947,7 @@ function buildPowerlineSetupMenuItems(powerline) {
67626
67947
  ];
67627
67948
  }
67628
67949
  function detectPowerlineFont() {
67629
- 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"];
67630
67951
  try {
67631
67952
  return dirs.some((dir) => existsSync16(dir) && readdirSync5(dir).some((file2) => /powerline|nerd font|meslo.*lg/i.test(file2)));
67632
67953
  } catch {
@@ -67634,11 +67955,11 @@ function detectPowerlineFont() {
67634
67955
  }
67635
67956
  }
67636
67957
  function PowerlineSetup({ settings, onUpdate, onBack }) {
67637
- const [screen, setScreen] = import_react45.useState("menu");
67638
- const [selected, setSelected] = import_react45.useState(0);
67639
- 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);
67640
67961
  const browserRuntime = process.env.CXSTATUSLINE_WEB === "1";
67641
- const fontFound = import_react45.useMemo(() => browserRuntime ? false : detectPowerlineFont(), [browserRuntime]);
67962
+ const fontFound = import_react51.useMemo(() => browserRuntime ? false : detectPowerlineFont(), [browserRuntime]);
67642
67963
  const powerline = settings.powerline;
67643
67964
  const manualSeparators = settings.lines.some((line3) => line3.some((item) => item.type === "separator"));
67644
67965
  use_input_default((input2, key) => {
@@ -67660,7 +67981,7 @@ function PowerlineSetup({ settings, onUpdate, onBack }) {
67660
67981
  }
67661
67982
  });
67662
67983
  if (screen === "separator" || screen === "startCap" || screen === "endCap") {
67663
- return /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(PowerlineSeparatorEditor, {
67984
+ return /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(PowerlineSeparatorEditor, {
67664
67985
  settings,
67665
67986
  mode: screen,
67666
67987
  onUpdate,
@@ -67668,23 +67989,23 @@ function PowerlineSetup({ settings, onUpdate, onBack }) {
67668
67989
  }, undefined, false, undefined, this);
67669
67990
  }
67670
67991
  if (screen === "themes")
67671
- return /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(PowerlineThemeSelector, {
67992
+ return /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(PowerlineThemeSelector, {
67672
67993
  settings,
67673
67994
  onUpdate,
67674
67995
  onBack: () => setScreen("menu")
67675
67996
  }, undefined, false, undefined, this);
67676
67997
  if (confirmEnable) {
67677
- return /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Box_default, {
67998
+ return /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Box_default, {
67678
67999
  flexDirection: "column",
67679
68000
  children: [
67680
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68001
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67681
68002
  color: "yellow",
67682
68003
  children: "Enabling Powerline removes manual separators from the status lines."
67683
68004
  }, undefined, false, undefined, this),
67684
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68005
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67685
68006
  children: "Continue?"
67686
68007
  }, undefined, false, undefined, this),
67687
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(ConfirmDialog, {
68008
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(ConfirmDialog, {
67688
68009
  inline: true,
67689
68010
  onConfirm: () => {
67690
68011
  onUpdate(buildEnabledPowerlineSettings(settings, true));
@@ -67695,53 +68016,53 @@ function PowerlineSetup({ settings, onUpdate, onBack }) {
67695
68016
  ]
67696
68017
  }, undefined, true, undefined, this);
67697
68018
  }
67698
- return /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Box_default, {
68019
+ return /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Box_default, {
67699
68020
  flexDirection: "column",
67700
68021
  children: [
67701
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68022
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67702
68023
  bold: true,
67703
68024
  children: "Powerline Setup"
67704
68025
  }, undefined, false, undefined, this),
67705
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68026
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67706
68027
  dimColor: true,
67707
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)`
67708
68029
  }, undefined, false, undefined, this),
67709
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68030
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67710
68031
  children: [
67711
68032
  "Powerline Mode: ",
67712
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68033
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67713
68034
  color: powerline.enabled ? "green" : "red",
67714
68035
  children: powerline.enabled ? "Enabled" : "Disabled"
67715
68036
  }, undefined, false, undefined, this),
67716
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68037
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67717
68038
  dimColor: true,
67718
68039
  children: " — press (t) to toggle"
67719
68040
  }, undefined, false, undefined, this)
67720
68041
  ]
67721
68042
  }, undefined, true, undefined, this),
67722
- powerline.enabled && /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(jsx_dev_runtime24.Fragment, {
68043
+ powerline.enabled && /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(jsx_dev_runtime26.Fragment, {
67723
68044
  children: [
67724
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68045
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67725
68046
  children: [
67726
68047
  "Align Widgets: ",
67727
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68048
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67728
68049
  color: powerline.autoAlign ? "green" : "red",
67729
68050
  children: powerline.autoAlign ? "Enabled" : "Disabled"
67730
68051
  }, undefined, false, undefined, this),
67731
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68052
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67732
68053
  dimColor: true,
67733
68054
  children: " — press (a) to toggle"
67734
68055
  }, undefined, false, undefined, this)
67735
68056
  ]
67736
68057
  }, undefined, true, undefined, this),
67737
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68058
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67738
68059
  children: [
67739
68060
  "Continue Theme: ",
67740
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68061
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67741
68062
  color: powerline.continueThemeAcrossLines ? "green" : "red",
67742
68063
  children: powerline.continueThemeAcrossLines ? "Enabled" : "Disabled"
67743
68064
  }, undefined, false, undefined, this),
67744
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68065
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67745
68066
  dimColor: true,
67746
68067
  children: " — press (c) to toggle"
67747
68068
  }, undefined, false, undefined, this)
@@ -67749,11 +68070,11 @@ function PowerlineSetup({ settings, onUpdate, onBack }) {
67749
68070
  }, undefined, true, undefined, this)
67750
68071
  ]
67751
68072
  }, undefined, true, undefined, this),
67752
- !powerline.enabled && /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text, {
68073
+ !powerline.enabled && /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text, {
67753
68074
  dimColor: true,
67754
68075
  children: "Enable Powerline mode to configure separators, caps, and themes."
67755
68076
  }, undefined, false, undefined, this),
67756
- /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(List, {
68077
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(List, {
67757
68078
  marginTop: 1,
67758
68079
  items: buildPowerlineSetupMenuItems(powerline),
67759
68080
  initialSelection: selected,
@@ -67771,7 +68092,7 @@ function PowerlineSetup({ settings, onUpdate, onBack }) {
67771
68092
  }
67772
68093
 
67773
68094
  // src/tui/App.tsx
67774
- var jsx_dev_runtime25 = __toESM(require_jsx_dev_runtime(), 1);
68095
+ var jsx_dev_runtime27 = __toESM(require_jsx_dev_runtime(), 1);
67775
68096
  var readImportFileFromDisk = (file2) => readFile2(file2, "utf8");
67776
68097
  function cloneSettings(settings) {
67777
68098
  const clone3 = globalThis.structuredClone;
@@ -67786,26 +68107,26 @@ function App2({ initialSettings, settingsPath, readImportFile = readImportFileFr
67786
68107
  const { exit: nativeExit } = use_app_default();
67787
68108
  const exit = onExit ?? nativeExit;
67788
68109
  const { stdout } = use_stdout_default();
67789
- const [settings, setSettings] = import_react46.useState(() => initialSettings ? clampSettings(initialSettings) : null);
67790
- const [originalSettings, setOriginalSettings] = import_react46.useState(() => initialSettings ? clampSettings(initialSettings) : null);
67791
- const [screen, setScreen] = import_react46.useState("main");
67792
- const [selectedLine, setSelectedLine] = import_react46.useState(0);
67793
- const [colorLine, setColorLine] = import_react46.useState(null);
67794
- const [flash, setFlash] = import_react46.useState(null);
67795
- const [importError, setImportError] = import_react46.useState(null);
67796
- const [importPreview, setImportPreview] = import_react46.useState(null);
67797
- const [importApplying, setImportApplying] = import_react46.useState(false);
67798
- const [terminalWidth, setTerminalWidth] = import_react46.useState(() => stdout.columns || 80);
67799
- const importGeneration = import_react46.useRef(0);
67800
- const importApplyPending = import_react46.useRef(false);
67801
- 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(() => {
67802
68123
  const updateWidth = () => setTerminalWidth(stdout.columns || 80);
67803
68124
  stdout.on("resize", updateWidth);
67804
68125
  return () => {
67805
68126
  stdout.off("resize", updateWidth);
67806
68127
  };
67807
68128
  }, [stdout]);
67808
- import_react46.useEffect(() => {
68129
+ import_react52.useEffect(() => {
67809
68130
  if (initialSettings)
67810
68131
  return;
67811
68132
  let active = true;
@@ -67830,10 +68151,10 @@ function App2({ initialSettings, settingsPath, readImportFile = readImportFileFr
67830
68151
  active = false;
67831
68152
  };
67832
68153
  }, [initialSettings, settingsPath]);
67833
- import_react46.useEffect(() => () => {
68154
+ import_react52.useEffect(() => () => {
67834
68155
  importGeneration.current += 1;
67835
68156
  }, []);
67836
- 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]);
67837
68158
  const replaceSettings = (next) => setSettings(clampSettings(next));
67838
68159
  const beginEdit = (nextScreen) => {
67839
68160
  if (!settings)
@@ -67975,45 +68296,45 @@ function App2({ initialSettings, settingsPath, readImportFile = readImportFileFr
67975
68296
  }
67976
68297
  };
67977
68298
  if (!settings) {
67978
- return /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Box_default, {
67979
- children: /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
68299
+ return /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(Box_default, {
68300
+ children: /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(Text, {
67980
68301
  children: "Loading configuration…"
67981
68302
  }, undefined, false, undefined, this)
67982
68303
  }, undefined, false, undefined, this);
67983
68304
  }
67984
- return /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Box_default, {
68305
+ return /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(Box_default, {
67985
68306
  flexDirection: "column",
67986
68307
  children: [
67987
- /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
68308
+ /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(Text, {
67988
68309
  bold: true,
67989
68310
  children: "cxstatusline Configuration"
67990
68311
  }, undefined, false, undefined, this),
67991
- flash && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
68312
+ flash && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(Text, {
67992
68313
  color: "yellow",
67993
68314
  children: flash
67994
68315
  }, undefined, false, undefined, this),
67995
- /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Box_default, {
68316
+ /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(Box_default, {
67996
68317
  marginTop: 1,
67997
68318
  flexDirection: "column",
67998
68319
  children: [
67999
- /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Text, {
68320
+ /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(Text, {
68000
68321
  dimColor: true,
68001
68322
  children: "> Preview"
68002
68323
  }, undefined, false, undefined, this),
68003
- /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(StatusLinePreview, {
68324
+ /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(StatusLinePreview, {
68004
68325
  settings,
68005
68326
  terminalWidth
68006
68327
  }, undefined, false, undefined, this)
68007
68328
  ]
68008
68329
  }, undefined, true, undefined, this),
68009
- /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Box_default, {
68330
+ /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(Box_default, {
68010
68331
  marginTop: 1,
68011
68332
  children: [
68012
- screen === "main" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(MainMenu, {
68333
+ screen === "main" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(MainMenu, {
68013
68334
  hasChanges,
68014
68335
  onSelect: (value) => handleMainMenu(value)
68015
68336
  }, undefined, false, undefined, this),
68016
- screen === "lines" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(LineSelector, {
68337
+ screen === "lines" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(LineSelector, {
68017
68338
  lines: settings.lines,
68018
68339
  onSelect: (line3) => {
68019
68340
  setSelectedLine(line3);
@@ -68024,59 +68345,59 @@ function App2({ initialSettings, settingsPath, readImportFile = readImportFileFr
68024
68345
  title: "Edit Lines",
68025
68346
  allowEditing: true
68026
68347
  }, undefined, false, undefined, this),
68027
- screen === "items" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(ItemsEditor, {
68348
+ screen === "items" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(ItemsEditor, {
68028
68349
  widgets: settings.lines[selectedLine] ?? [],
68029
68350
  onUpdate: (widgets) => updateLine(selectedLine, widgets),
68030
68351
  onBack: () => setScreen("lines"),
68031
68352
  lineNumber: selectedLine + 1,
68032
68353
  settings
68033
68354
  }, undefined, false, undefined, this),
68034
- screen === "colors" && colorLine === null && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(LineSelector, {
68355
+ screen === "colors" && colorLine === null && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(LineSelector, {
68035
68356
  lines: settings.lines,
68036
68357
  onSelect: setColorLine,
68037
68358
  onBack: () => finishEdit(),
68038
68359
  title: "Edit Colors"
68039
68360
  }, undefined, false, undefined, this),
68040
- screen === "colors" && colorLine !== null && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(ColorMenu, {
68361
+ screen === "colors" && colorLine !== null && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(ColorMenu, {
68041
68362
  widgets: settings.lines[colorLine] ?? [],
68042
68363
  lineIndex: colorLine,
68043
68364
  settings,
68044
68365
  onUpdate: (widgets) => updateLine(colorLine, widgets),
68045
68366
  onBack: () => setColorLine(null)
68046
68367
  }, undefined, false, undefined, this),
68047
- screen === "powerline" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(PowerlineSetup, {
68368
+ screen === "powerline" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(PowerlineSetup, {
68048
68369
  settings,
68049
68370
  onUpdate: replaceSettings,
68050
68371
  onBack: () => finishEdit()
68051
68372
  }, undefined, false, undefined, this),
68052
- screen === "overrides" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(GlobalOverridesMenu, {
68373
+ screen === "overrides" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(GlobalOverridesMenu, {
68053
68374
  settings,
68054
68375
  onUpdate: replaceSettings,
68055
68376
  onBack: () => finishEdit()
68056
68377
  }, undefined, false, undefined, this),
68057
- screen === "export" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(ExportConfigDialog, {
68378
+ screen === "export" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(ExportConfigDialog, {
68058
68379
  initialPath: `${settingsPath}.export.json`,
68059
68380
  onExport: exportSettings,
68060
68381
  onCancel: () => finishEdit()
68061
68382
  }, undefined, false, undefined, this),
68062
- screen === "import" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(ImportConfigDialog, {
68383
+ screen === "import" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(ImportConfigDialog, {
68063
68384
  error: importError,
68064
68385
  onFileChosen: importSettings,
68065
68386
  onCancel: () => finishEdit()
68066
68387
  }, undefined, false, undefined, this),
68067
- screen === "import-preview" && importPreview && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(ImportPreviewDialog, {
68388
+ screen === "import-preview" && importPreview && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(ImportPreviewDialog, {
68068
68389
  preview: importPreview,
68069
68390
  terminalWidth,
68070
68391
  busy: importApplying,
68071
68392
  onConfirm: () => void applyImport(),
68072
68393
  onCancel: () => finishEdit()
68073
68394
  }, undefined, false, undefined, this),
68074
- screen === "confirm-save" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(ConfirmDialog, {
68395
+ screen === "confirm-save" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(ConfirmDialog, {
68075
68396
  message: "Save the current configuration and exit?",
68076
68397
  onConfirm: () => void saveAndExit(),
68077
68398
  onCancel: () => setScreen("main")
68078
68399
  }, undefined, false, undefined, this),
68079
- screen === "confirm-discard" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(ConfirmDialog, {
68400
+ screen === "confirm-discard" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(ConfirmDialog, {
68080
68401
  message: hasChanges ? "Discard unsaved changes and exit?" : "Exit without saving?",
68081
68402
  onConfirm: () => {
68082
68403
  if (originalSettings)
@@ -68085,7 +68406,7 @@ function App2({ initialSettings, settingsPath, readImportFile = readImportFileFr
68085
68406
  },
68086
68407
  onCancel: () => setScreen("main")
68087
68408
  }, undefined, false, undefined, this),
68088
- screen === "confirm-invalid-replace" && /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(ConfirmDialog, {
68409
+ screen === "confirm-invalid-replace" && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(ConfirmDialog, {
68089
68410
  message: "Existing settings could not be parsed and have not been changed. Use default settings in memory? Saving later will replace the file.",
68090
68411
  onConfirm: () => {
68091
68412
  const defaults2 = clampSettings(DEFAULT_SETTINGS);
@@ -68102,7 +68423,7 @@ function App2({ initialSettings, settingsPath, readImportFile = readImportFileFr
68102
68423
  }
68103
68424
  async function runTUI(settingsPath) {
68104
68425
  process.stdout.write("\x1B[2J\x1B[H");
68105
- const instance = render_default(/* @__PURE__ */ jsx_dev_runtime25.jsxDEV(App2, {
68426
+ const instance = render_default(/* @__PURE__ */ jsx_dev_runtime27.jsxDEV(App2, {
68106
68427
  settingsPath
68107
68428
  }, undefined, false, undefined, this));
68108
68429
  await instance.waitUntilExit();
@@ -68153,7 +68474,7 @@ var USAGE = `usage: cxstatusline [command]
68153
68474
  install the published Codex pair (--compile builds it from source)
68154
68475
  patch [--force] build and install the patched Codex from source
68155
68476
  patch --simulate-drift <v> record <v> as the installed version so the next session sees drift
68156
- 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
68157
68478
  hook [install|uninstall] manage the SessionStart entry; bare 'hook' is what Codex runs
68158
68479
  doctor report toolchain, drift, hook and wrapper state
68159
68480
  policy [get|set <policy>] view or update policy (every, stable-minors, manual)
@@ -68235,10 +68556,25 @@ async function installCommand(argv, io2, deps) {
68235
68556
  }
68236
68557
  const ctx = contextFor(io2, deps);
68237
68558
  if (io2.isTTY === true && !yes && !codexVersion) {
68559
+ let manifest;
68238
68560
  try {
68239
- 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) {
68240
68568
  const supported = supportedCodexVersions(manifest);
68241
68569
  if (supported.length > 0) {
68570
+ let prebuiltVersions;
68571
+ if (!compile3) {
68572
+ try {
68573
+ prebuiltVersions = await fetchPublishedPrebuiltVersions(deps.transport?.fetch);
68574
+ } catch {
68575
+ prebuiltVersions = undefined;
68576
+ }
68577
+ }
68242
68578
  let defaultVersion;
68243
68579
  try {
68244
68580
  const located = upstreamFor(ctx, loadState(ctx));
@@ -68247,21 +68583,36 @@ async function installCommand(argv, io2, deps) {
68247
68583
  if (upstream) {
68248
68584
  const semverStr = `${upstream.major}.${upstream.minor}.${upstream.patch}`;
68249
68585
  if (supported.includes(semverStr)) {
68250
- defaultVersion = semverStr;
68586
+ if (compile3 || !prebuiltVersions || prebuiltVersions.includes(semverStr)) {
68587
+ defaultVersion = semverStr;
68588
+ }
68251
68589
  }
68252
68590
  }
68253
68591
  }
68254
68592
  } catch {}
68593
+ if (!defaultVersion && prebuiltVersions && prebuiltVersions.length > 0) {
68594
+ defaultVersion = supported.find((v2) => prebuiltVersions.includes(v2));
68595
+ }
68255
68596
  const prompter = deps.promptVersion ?? promptCodexVersion;
68256
- codexVersion = await prompter({
68597
+ const result2 = await prompter({
68257
68598
  supportedVersions: supported,
68599
+ prebuiltVersions,
68258
68600
  defaultVersion,
68601
+ compile: compile3,
68259
68602
  isTTY: true,
68260
68603
  say: (l) => io2.stdout(`${l}
68261
68604
  `)
68262
68605
  });
68606
+ if (result2 === null) {
68607
+ io2.stdout(`Installation cancelled.
68608
+ `);
68609
+ return 0;
68610
+ }
68611
+ const selection = typeof result2 === "string" ? { version: result2, compile: false } : result2;
68612
+ codexVersion = selection.version;
68613
+ compile3 = compile3 || selection.compile;
68263
68614
  }
68264
- } catch {}
68615
+ }
68265
68616
  }
68266
68617
  return runInstall(ctx, { compile: compile3, codexVersion }, deps.transport);
68267
68618
  }
@@ -68274,7 +68625,10 @@ async function updateCommand(argv, io2, deps) {
68274
68625
  }
68275
68626
  return runUpdate(contextFor(io2, deps), {
68276
68627
  compile: flags.includes("--compile"),
68277
- force: flags.includes("--force") || flags.includes("-y") || flags.includes("--yes")
68628
+ force: flags.includes("--force") || flags.includes("-y") || flags.includes("--yes"),
68629
+ isTTY: io2.isTTY,
68630
+ promptUpdate: deps.promptUpdate,
68631
+ fetchPrebuilts: deps.fetchPrebuilts
68278
68632
  }, deps.transport);
68279
68633
  }
68280
68634
  async function hookAcquireCommand(io2, deps) {
@@ -68362,12 +68716,17 @@ async function main(argv, io2, deps = {}) {
68362
68716
  return 2;
68363
68717
  }
68364
68718
 
68719
+ // src/utils/interactive.ts
68720
+ function canPrompt(stdin, stdout) {
68721
+ return Boolean(stdin.isTTY && stdout.isTTY);
68722
+ }
68723
+
68365
68724
  // src/cli.ts
68366
68725
  var argv = process.argv.slice(2);
68367
68726
  var isHook = argv.length === 1 && argv[0] === "hook";
68368
68727
  main(argv, {
68369
68728
  env: process.env,
68370
- isTTY: Boolean(process.stdin.isTTY),
68729
+ isTTY: canPrompt(process.stdin, process.stdout),
68371
68730
  stdin: () => {
68372
68731
  try {
68373
68732
  return readFileSync15(0, "utf8");