boo-flash 0.1.6 → 0.1.7

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.
Files changed (3) hide show
  1. package/README.md +13 -0
  2. package/dist/app.js +331 -407
  3. package/package.json +2 -3
package/README.md CHANGED
@@ -20,8 +20,21 @@ bunx boo-flash
20
20
 
21
21
  Choose the target computer’s GPU and USB drive. Boo Flash downloads and verifies the latest qualified image, then erases and writes the selected drive.
22
22
 
23
+ You can also choose a candidate. The selected version, candidate number (when applicable), and GPU stay visible through flashing and on the result screen.
24
+
23
25
  Requires Node.js 26.4+ or Bun 1.4+.
24
26
 
27
+ ## Development
28
+
29
+ From this directory, run `bun install --frozen-lockfile`, then `bun scripts/preview.tsx`
30
+ for a non-writing UI preview. It renders the same app with a separate fixture backend;
31
+ the preview label belongs to the development runner, not the app. The runner and
32
+ fixtures are neither bundled nor published. The installed CLI has no demo mode.
33
+
34
+ Run `bun run typecheck`, `bun run test` and `bun run test:package` for verification.
35
+ Package smoke tests start the real app and quit without selecting a drive; UI flow
36
+ tests supply their own backend.
37
+
25
38
  ## License
26
39
 
27
40
  MIT © 2026 Anomaly
package/dist/app.js CHANGED
@@ -2552,7 +2552,6 @@ import { createHash as createHash2 } from "node:crypto";
2552
2552
  import { chmod as chmod2, mkdtemp, open as open2, rm } from "node:fs/promises";
2553
2553
  import { tmpdir as tmpdir4 } from "node:os";
2554
2554
  import { dirname as dirname3, join as join5 } from "node:path";
2555
- import { setTimeout as delay } from "node:timers/promises";
2556
2555
  import { fileURLToPath as fileURLToPath2 } from "node:url";
2557
2556
 
2558
2557
  // src/backends/macos.ts
@@ -3567,105 +3566,40 @@ async function discoverCandidates(signal) {
3567
3566
  ], signal, { limit: 1024 ** 2 })));
3568
3567
  }
3569
3568
  var FlashBackend = class {
3570
- constructor(demo2) {
3571
- this.demo = demo2;
3572
- }
3573
- demo;
3574
- demoInstalled = false;
3575
3569
  requirePlatform() {
3576
3570
  if (process.platform === "darwin") return platform;
3577
3571
  if (process.platform === "linux") return platform2;
3578
- throw new Error("Boo Flash supports macOS and Linux. Use --demo for a non-writing preview.");
3572
+ throw new Error("Boo Flash supports macOS and Linux.");
3579
3573
  }
3580
3574
  get platformLabel() {
3581
- return this.demo ? "DEMO - no disks written" : this.requirePlatform().label;
3575
+ return this.requirePlatform().label;
3582
3576
  }
3583
3577
  get successTitle() {
3584
- return this.demo ? "Demo complete" : this.requirePlatform().successTitle;
3578
+ return this.requirePlatform().successTitle;
3585
3579
  }
3586
3580
  get successDetail() {
3587
- return this.demo ? "Simulated success only. No USB was written or ejected." : this.requirePlatform().successDetail;
3581
+ return this.requirePlatform().successDetail;
3588
3582
  }
3589
3583
  async clearCache(signal) {
3590
- if (this.demo) return "Demo only: no cached images or USB contents were changed.";
3591
3584
  return clearCachedImages(signal);
3592
3585
  }
3593
3586
  dependencies() {
3594
- if (!this.demo) return this.requirePlatform().dependencies();
3595
- const setup = this.demo.startsWith("setup") || this.demo === "no-homebrew";
3596
- return {
3597
- missing: !setup || this.demoInstalled ? [] : ["zstd"],
3598
- installer: this.demo === "no-homebrew" ? null : "Homebrew",
3599
- guidance: "Demo dependency guidance."
3600
- };
3587
+ return this.requirePlatform().dependencies();
3601
3588
  }
3602
3589
  async installDependencies(approved, signal, terminal) {
3603
- if (!this.demo) {
3604
- return terminal(() => this.requirePlatform().installDependencies(approved, signal));
3605
- }
3606
- await delay(2e3, void 0, { signal });
3607
- return terminal(async () => {
3608
- process.stdout.write("\nDEMO dependency setup: no software is installed.\nSimulating Homebrew terminal handoff. Ctrl-C cancels and quits.\n");
3609
- await delay(3e3);
3610
- if (this.demo === "setup-interrupted") process.stdout.write("Simulated Homebrew interruption result, without signaling Boo Flash. Quitting.\n");
3611
- if (signal.aborted || this.demo === "setup-interrupted") return "cancelled";
3612
- if (this.demo === "setup-error") throw new Error("Simulated Homebrew failure. No software was installed. Resolve the reported issue, then refresh to retry.");
3613
- this.demoInstalled = true;
3614
- return "installed";
3615
- });
3590
+ return terminal(() => this.requirePlatform().installDependencies(approved, signal));
3616
3591
  }
3617
3592
  async catalog(signal) {
3618
- if (!this.demo) return discoverImages(signal);
3619
- await delay(350, void 0, { signal });
3620
- return { run: 149, version: "0.1.0+149", revision: "9b7574859120add5a1a478bc7923aeb1629be4ba", timestamp: new Date(Date.now() - 10 * 60 * 1e3).toISOString(), images: profiles.map((profile, index) => ({
3621
- profile,
3622
- id: index,
3623
- name: `demo-${profile}`,
3624
- bytes: 1083197973,
3625
- digest: "demo"
3626
- })) };
3593
+ return discoverImages(signal);
3627
3594
  }
3628
3595
  async candidates(signal) {
3629
- if (!this.demo) return discoverCandidates(signal);
3630
- const catalog = await this.catalog(signal);
3631
- return this.demo === "empty" ? [] : [{
3632
- ...catalog,
3633
- timestamp: new Date(Date.now() - 5 * 60 * 1e3).toISOString(),
3634
- images: [catalog.images[0]],
3635
- candidate: { number: 1 }
3636
- }];
3596
+ return discoverCandidates(signal);
3637
3597
  }
3638
3598
  async disks(signal, staging = tmpdir4(), unmounted) {
3639
- if (this.demo) {
3640
- await delay(250, void 0, { signal });
3641
- return this.demo === "empty" ? [] : [
3642
- { id: "demo-usb-a", name: "SanDisk Ultra USB 3.0", bytes: 32 * 1024 ** 3, identity: "demo-a" },
3643
- { id: "demo-usb-b", name: "Kingston DataTraveler", bytes: 64 * 1024 ** 3, identity: "demo-b" }
3644
- ];
3645
- }
3646
3599
  if (process.getuid?.() === 0) throw new Error(`Run Boo Flash on ${this.requirePlatform().id === "macos" ? "macOS" : "Linux"} as your normal user, not with sudo.`);
3647
3600
  return this.requirePlatform().disks(signal, moduleDirectory, staging, unmounted);
3648
3601
  }
3649
3602
  async flash(catalog, image, disk, signal, update, authorize2) {
3650
- if (this.demo) {
3651
- if (!disk.id.startsWith("demo-") || image.digest !== "demo") throw new Error("Invalid demo selection.");
3652
- for (const stage of ["Downloading", "Verifying", "Unmounting", "Writing", "Flushing", "Ejecting"]) {
3653
- const total = stage === "Downloading" ? image.bytes : stage === "Writing" ? 8 * 1024 ** 3 : void 0;
3654
- for (let i = 0; i <= (total ? 30 : 5); i++) {
3655
- signal.throwIfAborted();
3656
- update({
3657
- stage,
3658
- detail: "Simulated activity. No disk commands are run.",
3659
- total,
3660
- bytes: total ? Math.round(total * i / 30) : void 0,
3661
- speed: total ? total / 3 : void 0
3662
- });
3663
- await delay(100, void 0, { signal });
3664
- if (this.demo === "error" && stage === "Writing" && i === 13) throw new Error("Demo write failure. No disks were written or ejected. Refresh to choose again.");
3665
- }
3666
- }
3667
- return;
3668
- }
3669
3603
  const platform3 = this.requirePlatform();
3670
3604
  if (process.getuid?.() === 0) throw new Error(`Run Boo Flash on ${platform3.id === "macos" ? "macOS" : "Linux"} as your normal user, not with sudo.`);
3671
3605
  if (!diskID3.test(disk.id) || !catalog.images.includes(image) || !profiles.includes(image.profile) || !positive(image.id) || !positive(image.bytes) || !sha256.test(image.digest)) throw new Error("Invalid flash selection.");
@@ -3790,7 +3724,6 @@ var FlashBackend = class {
3790
3724
  }
3791
3725
  }
3792
3726
  async authorize(signal) {
3793
- if (this.demo) return;
3794
3727
  if (process.getuid?.() === 0) throw new Error("Run Boo Flash as your normal user, not with sudo.");
3795
3728
  await this.requirePlatform().authorize(signal);
3796
3729
  }
@@ -3845,7 +3778,12 @@ function App(props) {
3845
3778
  const visible = () => dimensions().width >= 40 && dimensions().height >= 16;
3846
3779
  const options = () => screen() === "profile" ? 5 : screen() === "cleared" ? 1 : screen() === "candidates" ? Math.max(1, candidates().length) : screen() === "disks" ? disks3().length : 2;
3847
3780
  const percent = () => progress().total ? Math.min(100, Math.floor((progress().bytes ?? 0) / progress().total * 100)) : void 0;
3848
- const path = (d) => props.backend.demo ? d.id : `/dev/${d.id}`;
3781
+ const path = (d) => `/dev/${d.id}`;
3782
+ const selection = () => {
3783
+ const c = catalog(), i = image();
3784
+ if (!c || !i) return "";
3785
+ return `Boo ${c.version}${c.candidate ? ` candidate #${c.candidate.number}` : ""} / ${i.profile.toUpperCase()}${c.candidate ? ` / ${c.revision.slice(0, 7)}` : ""}`;
3786
+ };
3849
3787
  const operation = (work) => {
3850
3788
  controller = new AbortController();
3851
3789
  setStopping(false);
@@ -3856,7 +3794,7 @@ function App(props) {
3856
3794
  } catch (e) {
3857
3795
  if (!closing) {
3858
3796
  const setup = screen() === "installing";
3859
- setError(controller.signal.aborted && setup ? "Setup cancelled. Refresh to check what is still missing." : controller.signal.aborted && props.backend.demo ? "Demo cancelled. No disks were written or ejected." : e instanceof Error ? e.message : "Operation failed. Refresh and try again.");
3797
+ setError(controller.signal.aborted && setup ? "Setup cancelled. Refresh to check what is still missing." : e instanceof Error ? e.message : "Operation failed. Refresh and try again.");
3860
3798
  if (setup) setDependencies(props.backend.dependencies());
3861
3799
  setScreen(setup ? "setup" : "error");
3862
3800
  setCursor(0);
@@ -3881,6 +3819,7 @@ function App(props) {
3881
3819
  const refresh = () => {
3882
3820
  setError("");
3883
3821
  setCatalog(void 0);
3822
+ setImage(void 0);
3884
3823
  setDisk(void 0);
3885
3824
  setScreen("profile");
3886
3825
  setCursor(0);
@@ -3910,6 +3849,7 @@ function App(props) {
3910
3849
  if (state.missing.length) {
3911
3850
  setDependencies(state);
3912
3851
  setCatalog(void 0);
3852
+ setImage(void 0);
3913
3853
  setScreen("setup");
3914
3854
  setCursor(0);
3915
3855
  return;
@@ -4013,6 +3953,9 @@ function App(props) {
4013
3953
  await props.backend.flash(catalog(), image(), disk(), signal, setProgress, async () => {
4014
3954
  renderer.suspend();
4015
3955
  try {
3956
+ process.stdout.write(`
3957
+ ${selection()}
3958
+ `);
4016
3959
  await props.backend.authorize(signal);
4017
3960
  } finally {
4018
3961
  renderer.resume();
@@ -4094,7 +4037,7 @@ function App(props) {
4094
4037
  return _el$;
4095
4038
  })();
4096
4039
  return (() => {
4097
- var _el$4 = createElement("box"), _el$5 = createElement("box"), _el$6 = createElement("box"), _el$7 = createElement("text"), _el$9 = createElement("text"), _el$0 = createElement("box"), _el$1 = createElement("box"), _el$87 = createElement("text");
4040
+ var _el$4 = createElement("box"), _el$5 = createElement("box"), _el$6 = createElement("box"), _el$7 = createElement("text"), _el$9 = createElement("text"), _el$0 = createElement("box"), _el$1 = createElement("box"), _el$80 = createElement("text");
4098
4041
  insertNode(_el$4, _el$5);
4099
4042
  setProp(_el$4, "width", "100%");
4100
4043
  setProp(_el$4, "height", "100%");
@@ -4103,7 +4046,7 @@ function App(props) {
4103
4046
  insertNode(_el$5, _el$6);
4104
4047
  insertNode(_el$5, _el$0);
4105
4048
  insertNode(_el$5, _el$1);
4106
- insertNode(_el$5, _el$87);
4049
+ insertNode(_el$5, _el$80);
4107
4050
  setProp(_el$5, "border", true);
4108
4051
  setProp(_el$5, "borderStyle", "single");
4109
4052
  setProp(_el$5, "flexDirection", "column");
@@ -4127,56 +4070,67 @@ function App(props) {
4127
4070
  },
4128
4071
  get fallback() {
4129
4072
  return (() => {
4130
- var _el$88 = createElement("text");
4131
- insertNode(_el$88, createTextNode(`Enlarge the terminal to show the full choices and erase warning. Q quits.`));
4132
- effect((_$p) => setProp(_el$88, "fg", palette.warning, _$p));
4133
- return _el$88;
4073
+ var _el$81 = createElement("text");
4074
+ insertNode(_el$81, createTextNode(`Enlarge the terminal to show the full choices and erase warning. Q quits.`));
4075
+ effect((_$p) => setProp(_el$81, "fg", palette.warning, _$p));
4076
+ return _el$81;
4134
4077
  })();
4135
4078
  },
4136
4079
  get children() {
4137
4080
  return [createComponent2(Show, {
4081
+ get when() {
4082
+ return selection();
4083
+ },
4084
+ get children() {
4085
+ var _el$10 = createElement("text");
4086
+ setProp(_el$10, "flexShrink", 0);
4087
+ insert(_el$10, selection);
4088
+ effect((_$p) => setProp(_el$10, "fg", palette.foreground, _$p));
4089
+ return _el$10;
4090
+ }
4091
+ }), createComponent2(Show, {
4138
4092
  get when() {
4139
4093
  return screen() === "profile";
4140
4094
  },
4141
4095
  get children() {
4142
4096
  return [(() => {
4143
- var _el$10 = createElement("text");
4144
- insertNode(_el$10, createTextNode(`Choose the target computer's GPU`));
4097
+ var _el$11 = createElement("text");
4098
+ insertNode(_el$11, createTextNode(`Choose the target computer's GPU`));
4145
4099
  effect((_p$) => {
4146
4100
  var _v$5 = palette.foreground, _v$6 = TextAttributes2.BOLD;
4147
- _v$5 !== _p$.e && (_p$.e = setProp(_el$10, "fg", _v$5, _p$.e));
4148
- _v$6 !== _p$.t && (_p$.t = setProp(_el$10, "attributes", _v$6, _p$.t));
4101
+ _v$5 !== _p$.e && (_p$.e = setProp(_el$11, "fg", _v$5, _p$.e));
4102
+ _v$6 !== _p$.t && (_p$.t = setProp(_el$11, "attributes", _v$6, _p$.t));
4149
4103
  return _p$;
4150
4104
  }, {
4151
4105
  e: void 0,
4152
4106
  t: void 0
4153
4107
  });
4154
- return _el$10;
4108
+ return _el$11;
4155
4109
  })(), (() => {
4156
- var _el$12 = createElement("text");
4157
- insert(_el$12, (() => {
4110
+ var _el$13 = createElement("text");
4111
+ insert(_el$13, (() => {
4158
4112
  var _c$ = memo2(() => !!loading());
4159
4113
  return () => _c$() ? `${spinner()} Finding latest Boo release...` : memo2(() => !!catalog())() ? `Boo ${catalog().version} / ${catalog().revision.slice(0, 7)} / ${imageTime(catalog().timestamp, now())}` : "Dependencies needed. Enter to set up.";
4160
4114
  })());
4161
- effect((_$p) => setProp(_el$12, "fg", palette.muted, _$p));
4162
- return _el$12;
4115
+ effect((_$p) => setProp(_el$13, "fg", palette.muted, _$p));
4116
+ return _el$13;
4163
4117
  })(), (() => {
4164
- var _el$13 = createElement("box");
4165
- setProp(_el$13, "gap", 0);
4166
- setProp(_el$13, "marginBottom", 1);
4167
- setProp(_el$13, "flexShrink", 0);
4168
- insert(_el$13, createComponent2(For, {
4118
+ var _el$14 = createElement("box");
4119
+ setProp(_el$14, "gap", 0);
4120
+ setProp(_el$14, "marginBottom", 1);
4121
+ setProp(_el$14, "flexShrink", 0);
4122
+ insert(_el$14, createComponent2(For, {
4169
4123
  each: profiles,
4170
4124
  children: (profile, index) => row(profile.toUpperCase(), profile === "nvidia" ? "NVIDIA graphics" : `${profile === "intel" ? "Intel" : "AMD Radeon"} graphics`, index())
4171
4125
  }), null);
4172
- insert(_el$13, () => row("Candidates", "", 3), null);
4173
- insert(_el$13, () => row("Clear cached images", "", 4), null);
4174
- return _el$13;
4175
- })(), (() => {
4176
- var _el$14 = createElement("text");
4177
- insertNode(_el$14, createTextNode(`All images support Intel and AMD x86_64 CPUs.`));
4178
- effect((_$p) => setProp(_el$14, "fg", palette.muted, _$p));
4126
+ insert(_el$14, () => row("Candidates", "", 3), null);
4127
+ insert(_el$14, () => row("Clear cached images", "", 4), null);
4179
4128
  return _el$14;
4129
+ })(), (() => {
4130
+ var _el$15 = createElement("text");
4131
+ insertNode(_el$15, createTextNode(`All images support Intel and AMD x86_64 CPUs.`));
4132
+ effect((_$p) => setProp(_el$15, "fg", palette.muted, _$p));
4133
+ return _el$15;
4180
4134
  })()];
4181
4135
  }
4182
4136
  }), createComponent2(Show, {
@@ -4185,34 +4139,34 @@ function App(props) {
4185
4139
  },
4186
4140
  get children() {
4187
4141
  return [(() => {
4188
- var _el$16 = createElement("text");
4189
- insertNode(_el$16, createTextNode(`Clear cached images?`));
4142
+ var _el$17 = createElement("text");
4143
+ insertNode(_el$17, createTextNode(`Clear cached images?`));
4190
4144
  effect((_p$) => {
4191
4145
  var _v$7 = palette.warning, _v$8 = TextAttributes2.BOLD;
4192
- _v$7 !== _p$.e && (_p$.e = setProp(_el$16, "fg", _v$7, _p$.e));
4193
- _v$8 !== _p$.t && (_p$.t = setProp(_el$16, "attributes", _v$8, _p$.t));
4146
+ _v$7 !== _p$.e && (_p$.e = setProp(_el$17, "fg", _v$7, _p$.e));
4147
+ _v$8 !== _p$.t && (_p$.t = setProp(_el$17, "attributes", _v$8, _p$.t));
4194
4148
  return _p$;
4195
4149
  }, {
4196
4150
  e: void 0,
4197
4151
  t: void 0
4198
4152
  });
4199
- return _el$16;
4153
+ return _el$17;
4200
4154
  })(), (() => {
4201
- var _el$18 = createElement("text");
4202
- insertNode(_el$18, createTextNode(`Removes downloaded archives only, NOT USB contents. Active flashes are unaffected.`));
4203
- effect((_$p) => setProp(_el$18, "fg", palette.foreground, _$p));
4204
- return _el$18;
4155
+ var _el$19 = createElement("text");
4156
+ insertNode(_el$19, createTextNode(`Removes downloaded archives only, NOT USB contents. Active flashes are unaffected.`));
4157
+ effect((_$p) => setProp(_el$19, "fg", palette.foreground, _$p));
4158
+ return _el$19;
4205
4159
  })(), (() => {
4206
- var _el$20 = createElement("text");
4207
- insertNode(_el$20, createTextNode(`Images will download again when needed. Pending downloads may still finish and be cached.`));
4208
- effect((_$p) => setProp(_el$20, "fg", palette.muted, _$p));
4209
- return _el$20;
4160
+ var _el$21 = createElement("text");
4161
+ insertNode(_el$21, createTextNode(`Images will download again when needed. Pending downloads may still finish and be cached.`));
4162
+ effect((_$p) => setProp(_el$21, "fg", palette.muted, _$p));
4163
+ return _el$21;
4210
4164
  })(), (() => {
4211
- var _el$22 = createElement("box");
4212
- insert(_el$22, () => row("Go back", "", 0), null);
4213
- insert(_el$22, () => row(loading() ? "Clearing..." : "Clear cached images", "", 1, true), null);
4214
- effect((_$p) => setProp(_el$22, "gap", tight() ? 0 : 1, _$p));
4215
- return _el$22;
4165
+ var _el$23 = createElement("box");
4166
+ insert(_el$23, () => row("Go back", "", 0), null);
4167
+ insert(_el$23, () => row(loading() ? "Clearing..." : "Clear cached images", "", 1, true), null);
4168
+ effect((_$p) => setProp(_el$23, "gap", tight() ? 0 : 1, _$p));
4169
+ return _el$23;
4216
4170
  })()];
4217
4171
  }
4218
4172
  }), createComponent2(Show, {
@@ -4221,23 +4175,23 @@ function App(props) {
4221
4175
  },
4222
4176
  get children() {
4223
4177
  return [(() => {
4224
- var _el$23 = createElement("text");
4225
- insertNode(_el$23, createTextNode(`Cache cleared`));
4178
+ var _el$24 = createElement("text");
4179
+ insertNode(_el$24, createTextNode(`Cache cleared`));
4226
4180
  effect((_p$) => {
4227
4181
  var _v$9 = palette.success, _v$0 = TextAttributes2.BOLD;
4228
- _v$9 !== _p$.e && (_p$.e = setProp(_el$23, "fg", _v$9, _p$.e));
4229
- _v$0 !== _p$.t && (_p$.t = setProp(_el$23, "attributes", _v$0, _p$.t));
4182
+ _v$9 !== _p$.e && (_p$.e = setProp(_el$24, "fg", _v$9, _p$.e));
4183
+ _v$0 !== _p$.t && (_p$.t = setProp(_el$24, "attributes", _v$0, _p$.t));
4230
4184
  return _p$;
4231
4185
  }, {
4232
4186
  e: void 0,
4233
4187
  t: void 0
4234
4188
  });
4235
- return _el$23;
4189
+ return _el$24;
4236
4190
  })(), (() => {
4237
- var _el$25 = createElement("text");
4238
- insert(_el$25, notice);
4239
- effect((_$p) => setProp(_el$25, "fg", palette.foreground, _$p));
4240
- return _el$25;
4191
+ var _el$26 = createElement("text");
4192
+ insert(_el$26, notice);
4193
+ effect((_$p) => setProp(_el$26, "fg", palette.foreground, _$p));
4194
+ return _el$26;
4241
4195
  })(), memo2(() => row("Go back", "", 0))];
4242
4196
  }
4243
4197
  }), createComponent2(Show, {
@@ -4246,34 +4200,29 @@ function App(props) {
4246
4200
  },
4247
4201
  get children() {
4248
4202
  return [(() => {
4249
- var _el$26 = createElement("text");
4250
- insertNode(_el$26, createTextNode(`Candidates`));
4203
+ var _el$27 = createElement("text");
4204
+ insertNode(_el$27, createTextNode(`Candidates`));
4251
4205
  effect((_p$) => {
4252
4206
  var _v$1 = palette.foreground, _v$10 = TextAttributes2.BOLD;
4253
- _v$1 !== _p$.e && (_p$.e = setProp(_el$26, "fg", _v$1, _p$.e));
4254
- _v$10 !== _p$.t && (_p$.t = setProp(_el$26, "attributes", _v$10, _p$.t));
4207
+ _v$1 !== _p$.e && (_p$.e = setProp(_el$27, "fg", _v$1, _p$.e));
4208
+ _v$10 !== _p$.t && (_p$.t = setProp(_el$27, "attributes", _v$10, _p$.t));
4255
4209
  return _p$;
4256
4210
  }, {
4257
4211
  e: void 0,
4258
4212
  t: void 0
4259
4213
  });
4260
- return _el$26;
4261
- })(), (() => {
4262
- var _el$28 = createElement("text");
4263
- insertNode(_el$28, createTextNode(`Build-only; not boot/install/hardware qualified.`));
4264
- effect((_$p) => setProp(_el$28, "fg", palette.warning, _$p));
4265
- return _el$28;
4214
+ return _el$27;
4266
4215
  })(), createComponent2(Show, {
4267
4216
  get when() {
4268
4217
  return !loading();
4269
4218
  },
4270
4219
  get fallback() {
4271
4220
  return (() => {
4272
- var _el$90 = createElement("text"), _el$91 = createTextNode(` Finding completed candidates...`);
4273
- insertNode(_el$90, _el$91);
4274
- insert(_el$90, spinner, _el$91);
4275
- effect((_$p) => setProp(_el$90, "fg", palette.muted, _$p));
4276
- return _el$90;
4221
+ var _el$83 = createElement("text"), _el$84 = createTextNode(` Finding completed candidates...`);
4222
+ insertNode(_el$83, _el$84);
4223
+ insert(_el$83, spinner, _el$84);
4224
+ effect((_$p) => setProp(_el$83, "fg", palette.muted, _$p));
4225
+ return _el$83;
4277
4226
  })();
4278
4227
  },
4279
4228
  get children() {
@@ -4283,31 +4232,31 @@ function App(props) {
4283
4232
  },
4284
4233
  get fallback() {
4285
4234
  return [(() => {
4286
- var _el$92 = createElement("text");
4287
- insertNode(_el$92, createTextNode(`No completed candidates available`));
4288
- effect((_$p) => setProp(_el$92, "fg", palette.muted, _$p));
4289
- return _el$92;
4235
+ var _el$85 = createElement("text");
4236
+ insertNode(_el$85, createTextNode(`No completed candidates available`));
4237
+ effect((_$p) => setProp(_el$85, "fg", palette.muted, _$p));
4238
+ return _el$85;
4290
4239
  })(), memo2(() => row("Go back", "", 0))];
4291
4240
  },
4292
4241
  get children() {
4293
4242
  return [(() => {
4294
- var _el$30 = createElement("box");
4295
- setProp(_el$30, "gap", 0);
4296
- insert(_el$30, createComponent2(For, {
4243
+ var _el$29 = createElement("box");
4244
+ setProp(_el$29, "gap", 0);
4245
+ insert(_el$29, createComponent2(For, {
4297
4246
  get each() {
4298
4247
  return candidates().slice(Math.max(0, cursor() - 2), Math.max(3, cursor() + 1));
4299
4248
  },
4300
4249
  children: (c, index) => row(`${c.images[0].profile.toUpperCase()} ${c.revision.slice(0, 7)} #${c.candidate.number}`, imageTime(c.timestamp, now()), index() + Math.max(0, cursor() - 2), false, true)
4301
4250
  }));
4302
- return _el$30;
4251
+ return _el$29;
4303
4252
  })(), (() => {
4304
- var _el$31 = createElement("text"), _el$32 = createTextNode(` of `), _el$33 = createTextNode(` candidates / Enter to choose`);
4305
- insertNode(_el$31, _el$32);
4306
- insertNode(_el$31, _el$33);
4307
- insert(_el$31, () => cursor() + 1, _el$32);
4308
- insert(_el$31, () => candidates().length, _el$33);
4309
- effect((_$p) => setProp(_el$31, "fg", palette.muted, _$p));
4310
- return _el$31;
4253
+ var _el$30 = createElement("text"), _el$31 = createTextNode(` of `), _el$32 = createTextNode(` candidates / Enter to choose`);
4254
+ insertNode(_el$30, _el$31);
4255
+ insertNode(_el$30, _el$32);
4256
+ insert(_el$30, () => cursor() + 1, _el$31);
4257
+ insert(_el$30, () => candidates().length, _el$32);
4258
+ effect((_$p) => setProp(_el$30, "fg", palette.muted, _$p));
4259
+ return _el$30;
4311
4260
  })()];
4312
4261
  }
4313
4262
  });
@@ -4320,71 +4269,61 @@ function App(props) {
4320
4269
  },
4321
4270
  get children() {
4322
4271
  return [(() => {
4323
- var _el$34 = createElement("text");
4324
- insertNode(_el$34, createTextNode(`Set up required tools`));
4272
+ var _el$33 = createElement("text");
4273
+ insertNode(_el$33, createTextNode(`Set up required tools`));
4325
4274
  effect((_p$) => {
4326
4275
  var _v$11 = palette.accent, _v$12 = TextAttributes2.BOLD;
4327
- _v$11 !== _p$.e && (_p$.e = setProp(_el$34, "fg", _v$11, _p$.e));
4328
- _v$12 !== _p$.t && (_p$.t = setProp(_el$34, "attributes", _v$12, _p$.t));
4276
+ _v$11 !== _p$.e && (_p$.e = setProp(_el$33, "fg", _v$11, _p$.e));
4277
+ _v$12 !== _p$.t && (_p$.t = setProp(_el$33, "attributes", _v$12, _p$.t));
4329
4278
  return _p$;
4330
4279
  }, {
4331
4280
  e: void 0,
4332
4281
  t: void 0
4333
4282
  });
4334
- return _el$34;
4283
+ return _el$33;
4335
4284
  })(), (() => {
4336
- var _el$36 = createElement("text"), _el$37 = createTextNode(`Missing: `);
4337
- insertNode(_el$36, _el$37);
4338
- insert(_el$36, () => dependencies3().missing.join(", "), null);
4339
- effect((_$p) => setProp(_el$36, "fg", palette.foreground, _$p));
4340
- return _el$36;
4285
+ var _el$35 = createElement("text"), _el$36 = createTextNode(`Missing: `);
4286
+ insertNode(_el$35, _el$36);
4287
+ insert(_el$35, () => dependencies3().missing.join(", "), null);
4288
+ effect((_$p) => setProp(_el$35, "fg", palette.foreground, _$p));
4289
+ return _el$35;
4341
4290
  })(), createComponent2(Show, {
4342
4291
  get when() {
4343
4292
  return !error();
4344
4293
  },
4345
4294
  get fallback() {
4346
4295
  return (() => {
4347
- var _el$94 = createElement("text");
4348
- insert(_el$94, error);
4349
- effect((_$p) => setProp(_el$94, "fg", palette.warning, _$p));
4350
- return _el$94;
4296
+ var _el$87 = createElement("text");
4297
+ insert(_el$87, error);
4298
+ effect((_$p) => setProp(_el$87, "fg", palette.warning, _$p));
4299
+ return _el$87;
4351
4300
  })();
4352
4301
  },
4353
4302
  get children() {
4354
- var _el$38 = createElement("text");
4355
- insert(_el$38, (() => {
4303
+ var _el$37 = createElement("text");
4304
+ insert(_el$37, (() => {
4356
4305
  var _c$2 = memo2(() => !!dependencies3().installer);
4357
4306
  return () => _c$2() ? `${dependencies3().installer} will install ${dependencies3().missing.join(" and ")} and required dependencies, then continue.` : dependencies3().guidance;
4358
4307
  })());
4359
- effect((_$p) => setProp(_el$38, "fg", palette.muted, _$p));
4360
- return _el$38;
4308
+ effect((_$p) => setProp(_el$37, "fg", palette.muted, _$p));
4309
+ return _el$37;
4361
4310
  }
4362
4311
  }), createComponent2(Show, {
4363
4312
  get when() {
4364
4313
  return !tight();
4365
4314
  },
4366
4315
  get children() {
4367
- var _el$39 = createElement("text");
4368
- insert(_el$39, () => dependencies3().installer ? "Uses the ordinary terminal. Ctrl-C cancels and quits." : "Boo Flash will not change system packages on this platform.");
4369
- effect((_$p) => setProp(_el$39, "fg", palette.muted, _$p));
4370
- return _el$39;
4371
- }
4372
- }), createComponent2(Show, {
4373
- get when() {
4374
- return props.backend.demo;
4375
- },
4376
- get children() {
4377
- var _el$40 = createElement("text");
4378
- insertNode(_el$40, createTextNode(`Setup simulation; no software installed.`));
4379
- effect((_$p) => setProp(_el$40, "fg", palette.warning, _$p));
4380
- return _el$40;
4316
+ var _el$38 = createElement("text");
4317
+ insert(_el$38, () => dependencies3().installer ? "Uses the ordinary terminal. Ctrl-C cancels and quits." : "Boo Flash will not change system packages on this platform.");
4318
+ effect((_$p) => setProp(_el$38, "fg", palette.muted, _$p));
4319
+ return _el$38;
4381
4320
  }
4382
4321
  }), (() => {
4383
- var _el$42 = createElement("box");
4384
- insert(_el$42, () => row("Go back", "", 0), null);
4385
- insert(_el$42, () => row(dependencies3().installer ? `Install ${dependencies3().missing.join(" + ")}` : "Refresh", "", 1), null);
4386
- effect((_$p) => setProp(_el$42, "gap", tight() ? 0 : 1, _$p));
4387
- return _el$42;
4322
+ var _el$39 = createElement("box");
4323
+ insert(_el$39, () => row("Go back", "", 0), null);
4324
+ insert(_el$39, () => row(dependencies3().installer ? `Install ${dependencies3().missing.join(" + ")}` : "Refresh", "", 1), null);
4325
+ effect((_$p) => setProp(_el$39, "gap", tight() ? 0 : 1, _$p));
4326
+ return _el$39;
4388
4327
  })()];
4389
4328
  }
4390
4329
  }), createComponent2(Show, {
@@ -4393,44 +4332,34 @@ function App(props) {
4393
4332
  },
4394
4333
  get children() {
4395
4334
  return [(() => {
4396
- var _el$43 = createElement("text"), _el$44 = createTextNode(` `);
4397
- insertNode(_el$43, _el$44);
4398
- insert(_el$43, spinner, _el$44);
4399
- insert(_el$43, () => stopping() ? "Waiting for setup to stop..." : "Installing required tools", null);
4335
+ var _el$40 = createElement("text"), _el$41 = createTextNode(` `);
4336
+ insertNode(_el$40, _el$41);
4337
+ insert(_el$40, spinner, _el$41);
4338
+ insert(_el$40, () => stopping() ? "Waiting for setup to stop..." : "Installing required tools", null);
4400
4339
  effect((_p$) => {
4401
4340
  var _v$13 = palette.accent, _v$14 = TextAttributes2.BOLD;
4402
- _v$13 !== _p$.e && (_p$.e = setProp(_el$43, "fg", _v$13, _p$.e));
4403
- _v$14 !== _p$.t && (_p$.t = setProp(_el$43, "attributes", _v$14, _p$.t));
4341
+ _v$13 !== _p$.e && (_p$.e = setProp(_el$40, "fg", _v$13, _p$.e));
4342
+ _v$14 !== _p$.t && (_p$.t = setProp(_el$40, "attributes", _v$14, _p$.t));
4404
4343
  return _p$;
4405
4344
  }, {
4406
4345
  e: void 0,
4407
4346
  t: void 0
4408
4347
  });
4409
- return _el$43;
4348
+ return _el$40;
4410
4349
  })(), (() => {
4411
- var _el$45 = createElement("text"), _el$46 = createTextNode(` via `);
4412
- insertNode(_el$45, _el$46);
4413
- insert(_el$45, () => dependencies3().missing.join(" + "), _el$46);
4414
- insert(_el$45, () => dependencies3().installer, null);
4415
- effect((_$p) => setProp(_el$45, "fg", palette.foreground, _$p));
4416
- return _el$45;
4350
+ var _el$42 = createElement("text"), _el$43 = createTextNode(` via `);
4351
+ insertNode(_el$42, _el$43);
4352
+ insert(_el$42, () => dependencies3().missing.join(" + "), _el$43);
4353
+ insert(_el$42, () => dependencies3().installer, null);
4354
+ effect((_$p) => setProp(_el$42, "fg", palette.foreground, _$p));
4355
+ return _el$42;
4417
4356
  })(), (() => {
4418
- var _el$47 = createElement("text"), _el$48 = createTextNode(` uses the ordinary terminal. Ctrl-C cancels and quits; wait for cleanup.`);
4419
- insertNode(_el$47, _el$48);
4420
- insert(_el$47, () => dependencies3().installer, _el$48);
4421
- effect((_$p) => setProp(_el$47, "fg", palette.muted, _$p));
4422
- return _el$47;
4423
- })(), createComponent2(Show, {
4424
- get when() {
4425
- return props.backend.demo;
4426
- },
4427
- get children() {
4428
- var _el$49 = createElement("text");
4429
- insertNode(_el$49, createTextNode(`Setup simulation; no software installed.`));
4430
- effect((_$p) => setProp(_el$49, "fg", palette.warning, _$p));
4431
- return _el$49;
4432
- }
4433
- })];
4357
+ var _el$44 = createElement("text"), _el$45 = createTextNode(` uses the ordinary terminal. Ctrl-C cancels and quits; wait for cleanup.`);
4358
+ insertNode(_el$44, _el$45);
4359
+ insert(_el$44, () => dependencies3().installer, _el$45);
4360
+ effect((_$p) => setProp(_el$44, "fg", palette.muted, _$p));
4361
+ return _el$44;
4362
+ })()];
4434
4363
  }
4435
4364
  }), createComponent2(Show, {
4436
4365
  get when() {
@@ -4438,26 +4367,26 @@ function App(props) {
4438
4367
  },
4439
4368
  get children() {
4440
4369
  return [(() => {
4441
- var _el$51 = createElement("text");
4442
- insertNode(_el$51, createTextNode(`Choose a USB drive`));
4370
+ var _el$46 = createElement("text");
4371
+ insertNode(_el$46, createTextNode(`Choose a USB drive`));
4443
4372
  effect((_p$) => {
4444
4373
  var _v$15 = palette.foreground, _v$16 = TextAttributes2.BOLD;
4445
- _v$15 !== _p$.e && (_p$.e = setProp(_el$51, "fg", _v$15, _p$.e));
4446
- _v$16 !== _p$.t && (_p$.t = setProp(_el$51, "attributes", _v$16, _p$.t));
4374
+ _v$15 !== _p$.e && (_p$.e = setProp(_el$46, "fg", _v$15, _p$.e));
4375
+ _v$16 !== _p$.t && (_p$.t = setProp(_el$46, "attributes", _v$16, _p$.t));
4447
4376
  return _p$;
4448
4377
  }, {
4449
4378
  e: void 0,
4450
4379
  t: void 0
4451
4380
  });
4452
- return _el$51;
4381
+ return _el$46;
4453
4382
  })(), (() => {
4454
- var _el$53 = createElement("text");
4455
- insert(_el$53, (() => {
4383
+ var _el$48 = createElement("text");
4384
+ insert(_el$48, (() => {
4456
4385
  var _c$3 = memo2(() => !!loading());
4457
4386
  return () => _c$3() ? `${spinner()} Checking disks and protected storage...` : "System, home and app storage are excluded.";
4458
4387
  })());
4459
- effect((_$p) => setProp(_el$53, "fg", palette.muted, _$p));
4460
- return _el$53;
4388
+ effect((_$p) => setProp(_el$48, "fg", palette.muted, _$p));
4389
+ return _el$48;
4461
4390
  })(), createComponent2(Show, {
4462
4391
  get when() {
4463
4392
  return !loading();
@@ -4469,31 +4398,31 @@ function App(props) {
4469
4398
  },
4470
4399
  get fallback() {
4471
4400
  return (() => {
4472
- var _el$95 = createElement("text");
4473
- insertNode(_el$95, createTextNode(`No eligible USB drives. Connect a writable external USB drive, then press R to refresh.`));
4474
- effect((_$p) => setProp(_el$95, "fg", palette.warning, _$p));
4475
- return _el$95;
4401
+ var _el$88 = createElement("text");
4402
+ insertNode(_el$88, createTextNode(`No eligible USB drives. Connect a writable external USB drive, then press R to refresh.`));
4403
+ effect((_$p) => setProp(_el$88, "fg", palette.warning, _$p));
4404
+ return _el$88;
4476
4405
  })();
4477
4406
  },
4478
4407
  get children() {
4479
4408
  return [(() => {
4480
- var _el$54 = createElement("box");
4481
- setProp(_el$54, "gap", 0);
4482
- insert(_el$54, createComponent2(For, {
4409
+ var _el$49 = createElement("box");
4410
+ setProp(_el$49, "gap", 0);
4411
+ insert(_el$49, createComponent2(For, {
4483
4412
  get each() {
4484
4413
  return disks3().slice(Math.max(0, cursor() - 2), Math.max(3, cursor() + 1));
4485
4414
  },
4486
4415
  children: (d, index) => row(d.name, `${path(d)} / ${bytes(d.bytes)} / USB`, index() + Math.max(0, cursor() - 2))
4487
4416
  }));
4488
- return _el$54;
4417
+ return _el$49;
4489
4418
  })(), (() => {
4490
- var _el$55 = createElement("text");
4491
- insert(_el$55, (() => {
4419
+ var _el$50 = createElement("text");
4420
+ insert(_el$50, (() => {
4492
4421
  var _c$4 = memo2(() => cursor() < 0);
4493
4422
  return () => _c$4() ? "Use arrows to select a drive. Nothing is selected yet." : `${cursor() + 1} of ${disks3().length} drives / Enter to review`;
4494
4423
  })());
4495
- effect((_$p) => setProp(_el$55, "fg", palette.muted, _$p));
4496
- return _el$55;
4424
+ effect((_$p) => setProp(_el$50, "fg", palette.muted, _$p));
4425
+ return _el$50;
4497
4426
  })()];
4498
4427
  }
4499
4428
  });
@@ -4506,64 +4435,55 @@ function App(props) {
4506
4435
  },
4507
4436
  get children() {
4508
4437
  return [(() => {
4509
- var _el$56 = createElement("text");
4510
- insertNode(_el$56, createTextNode(`Erase this entire USB drive?`));
4438
+ var _el$51 = createElement("text");
4439
+ insertNode(_el$51, createTextNode(`Erase this entire USB drive?`));
4511
4440
  effect((_p$) => {
4512
4441
  var _v$17 = palette.warning, _v$18 = TextAttributes2.BOLD;
4513
- _v$17 !== _p$.e && (_p$.e = setProp(_el$56, "fg", _v$17, _p$.e));
4514
- _v$18 !== _p$.t && (_p$.t = setProp(_el$56, "attributes", _v$18, _p$.t));
4442
+ _v$17 !== _p$.e && (_p$.e = setProp(_el$51, "fg", _v$17, _p$.e));
4443
+ _v$18 !== _p$.t && (_p$.t = setProp(_el$51, "attributes", _v$18, _p$.t));
4515
4444
  return _p$;
4516
4445
  }, {
4517
4446
  e: void 0,
4518
4447
  t: void 0
4519
4448
  });
4520
- return _el$56;
4449
+ return _el$51;
4521
4450
  })(), (() => {
4522
- var _el$58 = createElement("box"), _el$59 = createElement("text"), _el$60 = createElement("text"), _el$61 = createElement("text"), _el$62 = createTextNode(` / `);
4523
- insertNode(_el$58, _el$59);
4524
- insertNode(_el$58, _el$60);
4525
- insertNode(_el$58, _el$61);
4526
- setProp(_el$58, "paddingX", 1);
4527
- setProp(_el$59, "height", 1);
4528
- setProp(_el$59, "wrapMode", "none");
4529
- insert(_el$59, () => disk()?.name);
4530
- insert(_el$60, (() => {
4451
+ var _el$53 = createElement("box"), _el$54 = createElement("text"), _el$55 = createElement("text");
4452
+ insertNode(_el$53, _el$54);
4453
+ insertNode(_el$53, _el$55);
4454
+ setProp(_el$53, "paddingX", 1);
4455
+ setProp(_el$54, "height", 1);
4456
+ setProp(_el$54, "wrapMode", "none");
4457
+ insert(_el$54, () => disk()?.name);
4458
+ insert(_el$55, (() => {
4531
4459
  var _c$5 = memo2(() => !!disk());
4532
4460
  return () => _c$5() ? `${path(disk())} / ${bytes(disk().bytes)}` : "";
4533
4461
  })());
4534
- insertNode(_el$61, _el$62);
4535
- insert(_el$61, () => image()?.profile.toUpperCase(), _el$62);
4536
- insert(_el$61, (() => {
4537
- var _c$6 = memo2(() => !!catalog()?.candidate);
4538
- return () => _c$6() ? `candidate (build-only) ${catalog()?.revision.slice(0, 7)}` : `Boo ${catalog()?.version}`;
4539
- })(), null);
4540
4462
  effect((_p$) => {
4541
- var _v$19 = palette.panelAlt, _v$20 = palette.foreground, _v$21 = TextAttributes2.BOLD, _v$22 = palette.accent, _v$23 = catalog()?.candidate ? palette.warning : palette.muted;
4542
- _v$19 !== _p$.e && (_p$.e = setProp(_el$58, "backgroundColor", _v$19, _p$.e));
4543
- _v$20 !== _p$.t && (_p$.t = setProp(_el$59, "fg", _v$20, _p$.t));
4544
- _v$21 !== _p$.a && (_p$.a = setProp(_el$59, "attributes", _v$21, _p$.a));
4545
- _v$22 !== _p$.o && (_p$.o = setProp(_el$60, "fg", _v$22, _p$.o));
4546
- _v$23 !== _p$.i && (_p$.i = setProp(_el$61, "fg", _v$23, _p$.i));
4463
+ var _v$19 = palette.panelAlt, _v$20 = palette.foreground, _v$21 = TextAttributes2.BOLD, _v$22 = palette.accent;
4464
+ _v$19 !== _p$.e && (_p$.e = setProp(_el$53, "backgroundColor", _v$19, _p$.e));
4465
+ _v$20 !== _p$.t && (_p$.t = setProp(_el$54, "fg", _v$20, _p$.t));
4466
+ _v$21 !== _p$.a && (_p$.a = setProp(_el$54, "attributes", _v$21, _p$.a));
4467
+ _v$22 !== _p$.o && (_p$.o = setProp(_el$55, "fg", _v$22, _p$.o));
4547
4468
  return _p$;
4548
4469
  }, {
4549
4470
  e: void 0,
4550
4471
  t: void 0,
4551
4472
  a: void 0,
4552
- o: void 0,
4553
- i: void 0
4473
+ o: void 0
4554
4474
  });
4555
- return _el$58;
4475
+ return _el$53;
4556
4476
  })(), (() => {
4557
- var _el$63 = createElement("text");
4558
- insertNode(_el$63, createTextNode(`ALL data and partitions on this drive will be lost. Back up anything you need before continuing.`));
4559
- effect((_$p) => setProp(_el$63, "fg", palette.warning, _$p));
4560
- return _el$63;
4477
+ var _el$56 = createElement("text");
4478
+ insertNode(_el$56, createTextNode(`ALL data and partitions on this drive will be lost. Back up anything you need before continuing.`));
4479
+ effect((_$p) => setProp(_el$56, "fg", palette.warning, _$p));
4480
+ return _el$56;
4561
4481
  })(), (() => {
4562
- var _el$65 = createElement("box");
4563
- insert(_el$65, () => row("Go back", "", 0), null);
4564
- insert(_el$65, () => row("Erase & flash", "", 1, true), null);
4565
- effect((_$p) => setProp(_el$65, "gap", tight() ? 0 : 1, _$p));
4566
- return _el$65;
4482
+ var _el$58 = createElement("box");
4483
+ insert(_el$58, () => row("Go back", "", 0), null);
4484
+ insert(_el$58, () => row("Erase & flash", "", 1, true), null);
4485
+ effect((_$p) => setProp(_el$58, "gap", tight() ? 0 : 1, _$p));
4486
+ return _el$58;
4567
4487
  })()];
4568
4488
  }
4569
4489
  }), createComponent2(Show, {
@@ -4572,108 +4492,114 @@ function App(props) {
4572
4492
  },
4573
4493
  get children() {
4574
4494
  return [(() => {
4575
- var _el$66 = createElement("text"), _el$67 = createTextNode(` `);
4576
- insertNode(_el$66, _el$67);
4577
- insert(_el$66, spinner, _el$67);
4578
- insert(_el$66, (() => {
4579
- var _c$7 = memo2(() => !!stopping());
4580
- return () => _c$7() ? "Stopping safely..." : progress().stage;
4495
+ var _el$59 = createElement("text"), _el$60 = createTextNode(` `);
4496
+ insertNode(_el$59, _el$60);
4497
+ insert(_el$59, spinner, _el$60);
4498
+ insert(_el$59, (() => {
4499
+ var _c$6 = memo2(() => !!stopping());
4500
+ return () => _c$6() ? "Stopping safely..." : progress().stage;
4581
4501
  })(), null);
4582
4502
  effect((_p$) => {
4583
- var _v$24 = palette.accent, _v$25 = TextAttributes2.BOLD;
4584
- _v$24 !== _p$.e && (_p$.e = setProp(_el$66, "fg", _v$24, _p$.e));
4585
- _v$25 !== _p$.t && (_p$.t = setProp(_el$66, "attributes", _v$25, _p$.t));
4503
+ var _v$23 = palette.accent, _v$24 = TextAttributes2.BOLD;
4504
+ _v$23 !== _p$.e && (_p$.e = setProp(_el$59, "fg", _v$23, _p$.e));
4505
+ _v$24 !== _p$.t && (_p$.t = setProp(_el$59, "attributes", _v$24, _p$.t));
4586
4506
  return _p$;
4587
4507
  }, {
4588
4508
  e: void 0,
4589
4509
  t: void 0
4590
4510
  });
4591
- return _el$66;
4511
+ return _el$59;
4592
4512
  })(), (() => {
4593
- var _el$68 = createElement("text"), _el$69 = createTextNode(` / `);
4594
- insertNode(_el$68, _el$69);
4595
- insert(_el$68, () => disk()?.name, _el$69);
4596
- insert(_el$68, () => image()?.profile.toUpperCase(), null);
4597
- effect((_$p) => setProp(_el$68, "fg", palette.foreground, _$p));
4598
- return _el$68;
4513
+ var _el$61 = createElement("text");
4514
+ insert(_el$61, () => disk()?.name);
4515
+ effect((_$p) => setProp(_el$61, "fg", palette.foreground, _$p));
4516
+ return _el$61;
4599
4517
  })(), (() => {
4600
- var _el$70 = createElement("text");
4601
- insert(_el$70, (() => {
4602
- var _c$8 = memo2(() => !!stopping());
4603
- return () => _c$8() ? "Waiting for all child processes to stop. Keep the USB connected." : progress().detail;
4518
+ var _el$62 = createElement("text");
4519
+ insert(_el$62, (() => {
4520
+ var _c$7 = memo2(() => !!stopping());
4521
+ return () => _c$7() ? "Waiting for all child processes to stop. Keep the USB connected." : progress().detail;
4604
4522
  })());
4605
- effect((_$p) => setProp(_el$70, "fg", palette.muted, _$p));
4606
- return _el$70;
4523
+ effect((_$p) => setProp(_el$62, "fg", palette.muted, _$p));
4524
+ return _el$62;
4607
4525
  })(), createComponent2(Show, {
4608
4526
  get when() {
4609
4527
  return percent() !== void 0;
4610
4528
  },
4611
4529
  get children() {
4612
4530
  return [(() => {
4613
- var _el$71 = createElement("box");
4614
- setProp(_el$71, "border", true);
4615
- setProp(_el$71, "height", 3);
4616
- insert(_el$71, createComponent2(Show, {
4531
+ var _el$63 = createElement("box");
4532
+ setProp(_el$63, "flexShrink", 0);
4533
+ insert(_el$63, createComponent2(Show, {
4617
4534
  get when() {
4618
4535
  return percent() > 0;
4619
4536
  },
4620
4537
  get children() {
4621
- var _el$72 = createElement("box");
4622
- setProp(_el$72, "height", 1);
4538
+ var _el$64 = createElement("box");
4539
+ setProp(_el$64, "height", 1);
4623
4540
  effect((_p$) => {
4624
- var _v$26 = `${percent() ?? 0}%`, _v$27 = palette.accent;
4625
- _v$26 !== _p$.e && (_p$.e = setProp(_el$72, "width", _v$26, _p$.e));
4626
- _v$27 !== _p$.t && (_p$.t = setProp(_el$72, "backgroundColor", _v$27, _p$.t));
4541
+ var _v$25 = `${percent() ?? 0}%`, _v$26 = palette.accent;
4542
+ _v$25 !== _p$.e && (_p$.e = setProp(_el$64, "width", _v$25, _p$.e));
4543
+ _v$26 !== _p$.t && (_p$.t = setProp(_el$64, "backgroundColor", _v$26, _p$.t));
4627
4544
  return _p$;
4628
4545
  }, {
4629
4546
  e: void 0,
4630
4547
  t: void 0
4631
4548
  });
4632
- return _el$72;
4549
+ return _el$64;
4633
4550
  }
4634
4551
  }));
4635
4552
  effect((_p$) => {
4636
- var _v$28 = palette.accent, _v$29 = palette.panelAlt;
4637
- _v$28 !== _p$.e && (_p$.e = setProp(_el$71, "borderColor", _v$28, _p$.e));
4638
- _v$29 !== _p$.t && (_p$.t = setProp(_el$71, "backgroundColor", _v$29, _p$.t));
4553
+ var _v$27 = !tight(), _v$28 = palette.accent, _v$29 = tight() ? 1 : 3, _v$30 = palette.panelAlt;
4554
+ _v$27 !== _p$.e && (_p$.e = setProp(_el$63, "border", _v$27, _p$.e));
4555
+ _v$28 !== _p$.t && (_p$.t = setProp(_el$63, "borderColor", _v$28, _p$.t));
4556
+ _v$29 !== _p$.a && (_p$.a = setProp(_el$63, "height", _v$29, _p$.a));
4557
+ _v$30 !== _p$.o && (_p$.o = setProp(_el$63, "backgroundColor", _v$30, _p$.o));
4639
4558
  return _p$;
4640
4559
  }, {
4641
4560
  e: void 0,
4642
- t: void 0
4561
+ t: void 0,
4562
+ a: void 0,
4563
+ o: void 0
4643
4564
  });
4644
- return _el$71;
4565
+ return _el$63;
4645
4566
  })(), (() => {
4646
- var _el$73 = createElement("text"), _el$74 = createTextNode(`% `), _el$75 = createTextNode(` / `);
4647
- insertNode(_el$73, _el$74);
4648
- insertNode(_el$73, _el$75);
4649
- insert(_el$73, percent, _el$74);
4650
- insert(_el$73, () => bytes(progress().bytes ?? 0), _el$75);
4651
- insert(_el$73, () => bytes(progress().total ?? 0), null);
4567
+ var _el$65 = createElement("text"), _el$66 = createTextNode(`% `), _el$67 = createTextNode(` / `);
4568
+ insertNode(_el$65, _el$66);
4569
+ insertNode(_el$65, _el$67);
4570
+ insert(_el$65, percent, _el$66);
4571
+ insert(_el$65, () => bytes(progress().bytes ?? 0), _el$67);
4572
+ insert(_el$65, () => bytes(progress().total ?? 0), null);
4652
4573
  effect((_p$) => {
4653
- var _v$30 = palette.foreground, _v$31 = TextAttributes2.BOLD;
4654
- _v$30 !== _p$.e && (_p$.e = setProp(_el$73, "fg", _v$30, _p$.e));
4655
- _v$31 !== _p$.t && (_p$.t = setProp(_el$73, "attributes", _v$31, _p$.t));
4574
+ var _v$31 = palette.foreground, _v$32 = TextAttributes2.BOLD;
4575
+ _v$31 !== _p$.e && (_p$.e = setProp(_el$65, "fg", _v$31, _p$.e));
4576
+ _v$32 !== _p$.t && (_p$.t = setProp(_el$65, "attributes", _v$32, _p$.t));
4656
4577
  return _p$;
4657
4578
  }, {
4658
4579
  e: void 0,
4659
4580
  t: void 0
4660
4581
  });
4661
- return _el$73;
4662
- })(), (() => {
4663
- var _el$76 = createElement("text");
4664
- insert(_el$76, (() => {
4665
- var _c$9 = memo2(() => !!progress().speed);
4666
- return () => _c$9() ? `${bytes(progress().speed)} / s` : "";
4667
- })());
4668
- effect((_$p) => setProp(_el$76, "fg", palette.muted, _$p));
4669
- return _el$76;
4670
- })()];
4582
+ return _el$65;
4583
+ })(), createComponent2(Show, {
4584
+ get when() {
4585
+ return !tight();
4586
+ },
4587
+ get children() {
4588
+ var _el$68 = createElement("text");
4589
+ insert(_el$68, (() => {
4590
+ var _c$8 = memo2(() => !!progress().speed);
4591
+ return () => _c$8() ? `${bytes(progress().speed)} / s` : "";
4592
+ })());
4593
+ effect((_$p) => setProp(_el$68, "fg", palette.muted, _$p));
4594
+ return _el$68;
4595
+ }
4596
+ })];
4671
4597
  }
4672
4598
  }), (() => {
4673
- var _el$77 = createElement("text");
4674
- insertNode(_el$77, createTextNode(`Keep the USB connected until safe removal succeeds.`));
4675
- effect((_$p) => setProp(_el$77, "fg", palette.warning, _$p));
4676
- return _el$77;
4599
+ var _el$69 = createElement("text");
4600
+ insertNode(_el$69, createTextNode(`Keep the USB connected until safe removal succeeds.`));
4601
+ effect((_$p) => setProp(_el$69, "fg", palette.warning, _$p));
4602
+ return _el$69;
4677
4603
  })()];
4678
4604
  }
4679
4605
  }), createComponent2(Show, {
@@ -4682,34 +4608,34 @@ function App(props) {
4682
4608
  },
4683
4609
  get children() {
4684
4610
  return [(() => {
4685
- var _el$79 = createElement("text");
4686
- insert(_el$79, () => props.backend.successTitle);
4611
+ var _el$71 = createElement("text");
4612
+ insert(_el$71, () => props.backend.successTitle);
4687
4613
  effect((_p$) => {
4688
- var _v$32 = palette.success, _v$33 = TextAttributes2.BOLD;
4689
- _v$32 !== _p$.e && (_p$.e = setProp(_el$79, "fg", _v$32, _p$.e));
4690
- _v$33 !== _p$.t && (_p$.t = setProp(_el$79, "attributes", _v$33, _p$.t));
4614
+ var _v$33 = palette.success, _v$34 = TextAttributes2.BOLD;
4615
+ _v$33 !== _p$.e && (_p$.e = setProp(_el$71, "fg", _v$33, _p$.e));
4616
+ _v$34 !== _p$.t && (_p$.t = setProp(_el$71, "attributes", _v$34, _p$.t));
4691
4617
  return _p$;
4692
4618
  }, {
4693
4619
  e: void 0,
4694
4620
  t: void 0
4695
4621
  });
4696
- return _el$79;
4622
+ return _el$71;
4697
4623
  })(), (() => {
4698
- var _el$80 = createElement("text");
4699
- insert(_el$80, () => props.backend.successDetail);
4700
- effect((_$p) => setProp(_el$80, "fg", palette.foreground, _$p));
4701
- return _el$80;
4624
+ var _el$72 = createElement("text");
4625
+ insert(_el$72, () => props.backend.successDetail);
4626
+ effect((_$p) => setProp(_el$72, "fg", palette.foreground, _$p));
4627
+ return _el$72;
4702
4628
  })(), (() => {
4703
- var _el$81 = createElement("text");
4704
- insert(_el$81, () => props.backend.demo ? "The real flow checks the write, flush and safe removal." : "Compressed image and raw stream verified. Not a device read-back.");
4705
- effect((_$p) => setProp(_el$81, "fg", palette.muted, _$p));
4706
- return _el$81;
4629
+ var _el$73 = createElement("text");
4630
+ insertNode(_el$73, createTextNode(`Compressed image and raw stream verified. Not a device read-back.`));
4631
+ effect((_$p) => setProp(_el$73, "fg", palette.muted, _$p));
4632
+ return _el$73;
4707
4633
  })(), (() => {
4708
- var _el$82 = createElement("box");
4709
- setProp(_el$82, "gap", 1);
4710
- insert(_el$82, () => row("Choose another image", "", 0), null);
4711
- insert(_el$82, () => row("Quit", "", 1), null);
4712
- return _el$82;
4634
+ var _el$75 = createElement("box");
4635
+ setProp(_el$75, "gap", 1);
4636
+ insert(_el$75, () => row("Choose another image", "", 0), null);
4637
+ insert(_el$75, () => row("Quit", "", 1), null);
4638
+ return _el$75;
4713
4639
  })()];
4714
4640
  }
4715
4641
  }), createComponent2(Show, {
@@ -4718,56 +4644,56 @@ function App(props) {
4718
4644
  },
4719
4645
  get children() {
4720
4646
  return [(() => {
4721
- var _el$83 = createElement("text");
4722
- insertNode(_el$83, createTextNode(`Flash not completed`));
4647
+ var _el$76 = createElement("text");
4648
+ insertNode(_el$76, createTextNode(`Flash not completed`));
4723
4649
  effect((_p$) => {
4724
- var _v$34 = palette.danger, _v$35 = TextAttributes2.BOLD;
4725
- _v$34 !== _p$.e && (_p$.e = setProp(_el$83, "fg", _v$34, _p$.e));
4726
- _v$35 !== _p$.t && (_p$.t = setProp(_el$83, "attributes", _v$35, _p$.t));
4650
+ var _v$35 = palette.danger, _v$36 = TextAttributes2.BOLD;
4651
+ _v$35 !== _p$.e && (_p$.e = setProp(_el$76, "fg", _v$35, _p$.e));
4652
+ _v$36 !== _p$.t && (_p$.t = setProp(_el$76, "attributes", _v$36, _p$.t));
4727
4653
  return _p$;
4728
4654
  }, {
4729
4655
  e: void 0,
4730
4656
  t: void 0
4731
4657
  });
4732
- return _el$83;
4658
+ return _el$76;
4733
4659
  })(), (() => {
4734
- var _el$85 = createElement("text");
4735
- insert(_el$85, error);
4736
- effect((_$p) => setProp(_el$85, "fg", palette.foreground, _$p));
4737
- return _el$85;
4660
+ var _el$78 = createElement("text");
4661
+ insert(_el$78, error);
4662
+ effect((_$p) => setProp(_el$78, "fg", palette.foreground, _$p));
4663
+ return _el$78;
4738
4664
  })(), (() => {
4739
- var _el$86 = createElement("box");
4740
- setProp(_el$86, "gap", 1);
4741
- insert(_el$86, () => row("Refresh & try again", "", 0), null);
4742
- insert(_el$86, () => row("Quit", "", 1), null);
4743
- return _el$86;
4665
+ var _el$79 = createElement("box");
4666
+ setProp(_el$79, "gap", 1);
4667
+ insert(_el$79, () => row("Refresh & try again", "", 0), null);
4668
+ insert(_el$79, () => row("Quit", "", 1), null);
4669
+ return _el$79;
4744
4670
  })()];
4745
4671
  }
4746
4672
  })];
4747
4673
  }
4748
4674
  }));
4749
- setProp(_el$87, "height", 1);
4750
- setProp(_el$87, "flexShrink", 0);
4751
- setProp(_el$87, "wrapMode", "none");
4752
- insert(_el$87, (() => {
4753
- var _c$0 = memo2(() => !!busy());
4754
- return () => _c$0() ? "Esc cancel / Q stop & quit" : dimensions().width < 56 ? "Arrows / Enter / Esc / R / Q quit" : "Arrows / Enter / Esc back / R refresh / Q quit";
4675
+ setProp(_el$80, "height", 1);
4676
+ setProp(_el$80, "flexShrink", 0);
4677
+ setProp(_el$80, "wrapMode", "none");
4678
+ insert(_el$80, (() => {
4679
+ var _c$9 = memo2(() => !!busy());
4680
+ return () => _c$9() ? "Esc cancel / Q stop & quit" : dimensions().width < 56 ? "Arrows / Enter / Esc / R / Q quit" : "Arrows / Enter / Esc back / R refresh / Q quit";
4755
4681
  })());
4756
4682
  effect((_p$) => {
4757
- var _v$36 = palette.background, _v$37 = dimensions().width <= 80 ? "100%" : 80, _v$38 = dimensions().height <= 24 ? "100%" : 24, _v$39 = palette.border, _v$40 = palette.card, _v$41 = palette.accent, _v$42 = TextAttributes2.BOLD, _v$43 = props.backend.demo ? palette.warning : palette.muted, _v$44 = palette.danger, _v$45 = tight() ? 0 : 1, _v$46 = tight() ? 0 : 1, _v$47 = tight() || (compact() || dimensions().width < 56) && screen() === "setup" ? 0 : 1, _v$48 = palette.muted;
4758
- _v$36 !== _p$.e && (_p$.e = setProp(_el$4, "backgroundColor", _v$36, _p$.e));
4759
- _v$37 !== _p$.t && (_p$.t = setProp(_el$5, "width", _v$37, _p$.t));
4760
- _v$38 !== _p$.a && (_p$.a = setProp(_el$5, "height", _v$38, _p$.a));
4761
- _v$39 !== _p$.o && (_p$.o = setProp(_el$5, "borderColor", _v$39, _p$.o));
4762
- _v$40 !== _p$.i && (_p$.i = setProp(_el$5, "backgroundColor", _v$40, _p$.i));
4763
- _v$41 !== _p$.n && (_p$.n = setProp(_el$7, "fg", _v$41, _p$.n));
4764
- _v$42 !== _p$.s && (_p$.s = setProp(_el$7, "attributes", _v$42, _p$.s));
4765
- _v$43 !== _p$.h && (_p$.h = setProp(_el$9, "fg", _v$43, _p$.h));
4766
- _v$44 !== _p$.r && (_p$.r = setProp(_el$0, "backgroundColor", _v$44, _p$.r));
4767
- _v$45 !== _p$.d && (_p$.d = setProp(_el$0, "marginTop", _v$45, _p$.d));
4768
- _v$46 !== _p$.l && (_p$.l = setProp(_el$1, "paddingTop", _v$46, _p$.l));
4769
- _v$47 !== _p$.u && (_p$.u = setProp(_el$1, "gap", _v$47, _p$.u));
4770
- _v$48 !== _p$.c && (_p$.c = setProp(_el$87, "fg", _v$48, _p$.c));
4683
+ var _v$37 = palette.background, _v$38 = dimensions().width <= 80 ? "100%" : 80, _v$39 = dimensions().height <= 24 ? "100%" : 24, _v$40 = palette.border, _v$41 = palette.card, _v$42 = palette.accent, _v$43 = TextAttributes2.BOLD, _v$44 = palette.muted, _v$45 = palette.danger, _v$46 = tight() ? 0 : 1, _v$47 = tight() ? 0 : 1, _v$48 = tight() || (compact() || dimensions().width < 56) && (screen() === "setup" || !!image()) ? 0 : 1, _v$49 = palette.muted;
4684
+ _v$37 !== _p$.e && (_p$.e = setProp(_el$4, "backgroundColor", _v$37, _p$.e));
4685
+ _v$38 !== _p$.t && (_p$.t = setProp(_el$5, "width", _v$38, _p$.t));
4686
+ _v$39 !== _p$.a && (_p$.a = setProp(_el$5, "height", _v$39, _p$.a));
4687
+ _v$40 !== _p$.o && (_p$.o = setProp(_el$5, "borderColor", _v$40, _p$.o));
4688
+ _v$41 !== _p$.i && (_p$.i = setProp(_el$5, "backgroundColor", _v$41, _p$.i));
4689
+ _v$42 !== _p$.n && (_p$.n = setProp(_el$7, "fg", _v$42, _p$.n));
4690
+ _v$43 !== _p$.s && (_p$.s = setProp(_el$7, "attributes", _v$43, _p$.s));
4691
+ _v$44 !== _p$.h && (_p$.h = setProp(_el$9, "fg", _v$44, _p$.h));
4692
+ _v$45 !== _p$.r && (_p$.r = setProp(_el$0, "backgroundColor", _v$45, _p$.r));
4693
+ _v$46 !== _p$.d && (_p$.d = setProp(_el$0, "marginTop", _v$46, _p$.d));
4694
+ _v$47 !== _p$.l && (_p$.l = setProp(_el$1, "paddingTop", _v$47, _p$.l));
4695
+ _v$48 !== _p$.u && (_p$.u = setProp(_el$1, "gap", _v$48, _p$.u));
4696
+ _v$49 !== _p$.c && (_p$.c = setProp(_el$80, "fg", _v$49, _p$.c));
4771
4697
  return _p$;
4772
4698
  }, {
4773
4699
  e: void 0,
@@ -4790,10 +4716,8 @@ function App(props) {
4790
4716
 
4791
4717
  // src/index.tsx
4792
4718
  var args = process.argv.slice(2);
4793
- var demo = args.includes("--demo");
4794
- var fixture = args.find((arg) => arg.startsWith("--demo="))?.slice(7);
4795
- if (args.length > 1 || args.some((arg) => !["--demo", "--demo=empty", "--demo=error", "--demo=setup", "--demo=setup-zstd", "--demo=setup-error", "--demo=setup-interrupted", "--demo=no-homebrew", "--list-images", "--clear-cache"].includes(arg))) {
4796
- console.error("Usage: bun start [--demo[=empty|error|setup|setup-zstd|setup-error|setup-interrupted|no-homebrew] | --list-images | --clear-cache]");
4719
+ if (args.length > 1 || args.some((arg) => !["--list-images", "--clear-cache"].includes(arg))) {
4720
+ console.error("Usage: boo-flash [--list-images | --clear-cache]");
4797
4721
  process.exitCode = 1;
4798
4722
  } else if (args.includes("--clear-cache")) {
4799
4723
  try {
@@ -4809,11 +4733,11 @@ if (args.length > 1 || args.some((arg) => !["--demo", "--demo=empty", "--demo=er
4809
4733
  console.error(e instanceof Error ? e.message : "Image discovery failed.");
4810
4734
  process.exitCode = 1;
4811
4735
  }
4812
- } else if (!demo && !fixture && (!["darwin", "linux"].includes(process.platform) || process.getuid?.() === 0)) {
4813
- console.error("Boo Flash requires macOS or Linux and a normal user account. Use --demo for a non-writing UI preview.");
4736
+ } else if (!["darwin", "linux"].includes(process.platform) || process.getuid?.() === 0) {
4737
+ console.error("Boo Flash requires macOS or Linux and a normal user account.");
4814
4738
  process.exitCode = 1;
4815
4739
  } else {
4816
- const backend = new FlashBackend(demo ? "normal" : fixture);
4740
+ const backend = new FlashBackend();
4817
4741
  const renderer = await createCliRenderer2({
4818
4742
  backgroundColor: palette.background,
4819
4743
  targetFps: 30,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "boo-flash",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Flash qualified Boo images to USB drives on macOS and Linux",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -32,9 +32,8 @@
32
32
  },
33
33
  "scripts": {
34
34
  "start": "bun src/index.tsx",
35
- "demo": "bun src/index.tsx --demo",
36
35
  "build": "./scripts/build.sh",
37
- "test": "bun test src/backends/linux.test.ts src/backend.test.ts",
36
+ "test": "bun test src/backends/linux.test.ts src/backend.test.ts src/App.test.tsx",
38
37
  "test:package": "./scripts/package-test.sh",
39
38
  "typecheck": "tsc --noEmit",
40
39
  "prepack": "bun run build"