boo-flash 0.1.4 → 0.1.6

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 (2) hide show
  1. package/dist/app.js +396 -431
  2. package/package.json +1 -1
package/dist/app.js CHANGED
@@ -2588,7 +2588,6 @@ function resolvePackage(name2) {
2588
2588
 
2589
2589
  // src/dependencies.ts
2590
2590
  var commonTools = ["curl", "zstd"];
2591
- var candidateTools = ["gh", "unzip"];
2592
2591
  function preferredExecutable(name2, platform3, path, macSystemExists) {
2593
2592
  if (platform3 === "darwin" && (name2 === "curl" || name2 === "unzip") && macSystemExists) return `/usr/bin/${name2}`;
2594
2593
  return path;
@@ -2643,7 +2642,7 @@ async function command(argv, signal, options = {}) {
2643
2642
  if (!binary) throw new Error(`Missing ${argv[0]}. Refresh dependency setup before continuing.`);
2644
2643
  const child = spawn(binary, argv.slice(1), {
2645
2644
  stdio: options.terminal ? "inherit" : ["pipe", "pipe", "pipe"],
2646
- env: { ...process.env, GH_DEBUG: "", GH_PAGER: "cat", PAGER: "cat", GH_PROMPT_DISABLED: "1" }
2645
+ env: { ...process.env, PAGER: "cat" }
2647
2646
  });
2648
2647
  let failure;
2649
2648
  const exited = new Promise((resolve) => {
@@ -2654,7 +2653,7 @@ async function command(argv, signal, options = {}) {
2654
2653
  });
2655
2654
  let stderr = "";
2656
2655
  child.stderr?.on("data", (data) => {
2657
- if (argv[0] !== "gh") stderr = (stderr + data.toString()).slice(-1500);
2656
+ stderr = (stderr + data.toString()).slice(-1500);
2658
2657
  });
2659
2658
  child.stdin?.on("error", (error) => {
2660
2659
  failure = error;
@@ -2677,8 +2676,7 @@ async function command(argv, signal, options = {}) {
2677
2676
  const code2 = await exited;
2678
2677
  signal.throwIfAborted();
2679
2678
  if (failure || code2 !== 0) {
2680
- const message = argv[0] === "gh" ? `GitHub request failed. Run ${cleanText(binary)} auth login if needed; check repository access and your connection, then refresh.` : `${argv[0].split("/").pop()} failed (${code2 ?? "not started"}). ${cleanText(stderr || failure?.message || "")}`;
2681
- throw new Error(message);
2679
+ throw new Error(`${argv[0].split("/").pop()} failed (${code2 ?? "not started"}). ${cleanText(stderr || failure?.message || "")}`);
2682
2680
  }
2683
2681
  return output;
2684
2682
  } finally {
@@ -2690,10 +2688,9 @@ async function command(argv, signal, options = {}) {
2690
2688
 
2691
2689
  // src/installers/homebrew.ts
2692
2690
  import { spawn as spawn2 } from "node:child_process";
2693
- var packages = [...commonTools, ...candidateTools];
2694
- function dependencies(includeGitHub = false) {
2695
- const required2 = includeGitHub ? packages : commonTools;
2696
- const absent = missing(required2);
2691
+ var packages = commonTools;
2692
+ function dependencies() {
2693
+ const absent = missing(packages);
2697
2694
  return {
2698
2695
  missing: absent,
2699
2696
  installer: absent.length ? executable("brew") : null,
@@ -2804,8 +2801,6 @@ async function disks(signal, source, staging = tmpdir(), unmounted) {
2804
2801
  const zstd = executable("zstd");
2805
2802
  if (!zstd) throw new Error("Install zstd before flashing.");
2806
2803
  protectedPaths2.push(zstd);
2807
- const gh = executable("gh");
2808
- if (gh) protectedPaths2.push(gh);
2809
2804
  for (const path of protectedPaths2) {
2810
2805
  const canonical = await realpath(path);
2811
2806
  const device = (await command(["/usr/bin/stat", "-f", "%Sd", canonical], signal)).trim();
@@ -3044,7 +3039,7 @@ async function protectedPaths(source, staging) {
3044
3039
  }
3045
3040
  }
3046
3041
  if (process.env.OTUI_ASSET_ROOT) paths.push(process.env.OTUI_ASSET_ROOT);
3047
- for (const name2 of [...commonTools, ...candidateTools, ...tools]) {
3042
+ for (const name2 of [...commonTools, ...tools]) {
3048
3043
  const path = executable(name2);
3049
3044
  if (path) paths.push(path);
3050
3045
  }
@@ -3239,8 +3234,8 @@ async function disks2(signal, source, staging = tmpdir2(), unmounted) {
3239
3234
  }
3240
3235
  return result;
3241
3236
  }
3242
- function dependencies2(includeGitHub = false) {
3243
- const required2 = [...commonTools, ...tools, ...includeGitHub ? candidateTools : []];
3237
+ function dependencies2() {
3238
+ const required2 = [...commonTools, ...tools];
3244
3239
  return {
3245
3240
  missing: missing(required2),
3246
3241
  installer: null,
@@ -3423,8 +3418,6 @@ async function clearCachedImages(signal) {
3423
3418
 
3424
3419
  // src/backend.ts
3425
3420
  var profiles = ["intel", "amd", "nvidia"];
3426
- var repository = "anomalyco/boo";
3427
- var repositoryIdentities = /* @__PURE__ */ new Set([repository, "anomalyco/ghostty-distro"]);
3428
3421
  var releaseOrigin = "https://images.os.boo";
3429
3422
  var diskID3 = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/;
3430
3423
  var sha256 = /^[a-f0-9]{64}$/;
@@ -3434,13 +3427,15 @@ var moduleDirectory = dirname3(fileURLToPath2(import.meta.url));
3434
3427
  function bytes(n) {
3435
3428
  return n >= 1024 ** 3 ? `${(n / 1024 ** 3).toFixed(1)} GiB` : `${(n / 1024 ** 2).toFixed(1)} MiB`;
3436
3429
  }
3437
- function localTimestamp(value) {
3430
+ function imageTime(value, now = Date.now(), locales) {
3438
3431
  const date = new Date(value);
3439
3432
  if (!Number.isFinite(date.getTime())) throw new Error("Invalid image timestamp.");
3440
- const part = (number) => String(number).padStart(2, "0");
3441
- const minutes = -date.getTimezoneOffset();
3442
- const offset = `${minutes < 0 ? "-" : "+"}${part(Math.floor(Math.abs(minutes) / 60))}:${part(Math.abs(minutes) % 60)}`;
3443
- return `${date.getFullYear()}-${part(date.getMonth() + 1)}-${part(date.getDate())} ${part(date.getHours())}:${part(date.getMinutes())}:${part(date.getSeconds())} ${offset}`;
3433
+ const age = now - date.getTime();
3434
+ if (age >= -60 * 1e3 && age <= 60 * 60 * 1e3) {
3435
+ const minutes = Math.max(0, Math.round(age / (60 * 1e3)));
3436
+ return new Intl.RelativeTimeFormat(locales, { numeric: "always" }).format(-minutes, "minute");
3437
+ }
3438
+ return new Intl.DateTimeFormat(locales, { dateStyle: "medium", timeStyle: "short" }).format(date);
3444
3439
  }
3445
3440
  function releaseTimestamp(headers) {
3446
3441
  const values = headers.split(/\r?\n/).flatMap((line) => {
@@ -3527,35 +3522,49 @@ async function discoverImages(signal) {
3527
3522
  });
3528
3523
  return { run: build, version: channel.version, revision: channel.revision, timestamp, images };
3529
3524
  }
3530
- async function discoverCandidates(signal) {
3531
- const api = async (path) => JSON.parse(await command(["gh", "api", "--hostname", "github.com", `repos/${repository}/${path}`], signal));
3532
- const result = await api("actions/workflows/candidate.yml/runs?status=success&per_page=10");
3533
- if (!Array.isArray(result.workflow_runs)) throw new Error("Invalid GitHub candidate workflow response.");
3534
- const candidates = [];
3535
- for (const run of result.workflow_runs.slice(0, 10)) {
3536
- if (run.status !== "completed" || run.conclusion !== "success" || run.path !== ".github/workflows/candidate.yml" || !positive(run.id) || !positive(run.run_number) || !Number.isFinite(Date.parse(run.created_at))) continue;
3537
- const batch = await api(`actions/runs/${run.id}/artifacts?per_page=100`);
3538
- if (!Array.isArray(batch.artifacts)) throw new Error("Invalid GitHub artifact response.");
3539
- for (const a of batch.artifacts) {
3540
- const match = /^boo-(intel|amd|nvidia)-candidate-([a-f0-9]{40})$/.exec(a.name);
3541
- if (!match || a.expired !== false || !(Date.parse(a.expires_at) > Date.now()) || !positive(a.id) || !positive(a.size_in_bytes) || !/^sha256:[a-f0-9]{64}$/.test(a.digest) || batch.artifacts.filter((other) => other.name === a.name).length !== 1) continue;
3542
- candidates.push({
3543
- run: run.id,
3544
- revision: match[2],
3545
- timestamp: new Date(run.created_at).toISOString(),
3546
- images: [{
3547
- profile: match[1],
3548
- id: a.id,
3549
- name: a.name,
3550
- bytes: a.size_in_bytes,
3551
- digest: a.digest.slice(7)
3552
- }],
3553
- candidate: { number: run.run_number, title: cleanText(run.display_title ?? "") }
3554
- });
3555
- if (candidates.length === 10) return candidates;
3525
+ function candidateCatalog(result) {
3526
+ if (result?.schema !== 1 || !Array.isArray(result.candidates) || result.candidates.length > 10) {
3527
+ throw new Error("Invalid Boo candidate catalog.");
3528
+ }
3529
+ return result.candidates.map((candidate) => {
3530
+ const profile = candidate?.profile;
3531
+ const image = candidate?.image;
3532
+ const name2 = `boo-${candidate?.version}-candidate-${candidate?.revision?.slice(0, 12)}-x86_64-${profile}.raw.zst`;
3533
+ if (!positive(candidate?.number) || !Number.isFinite(Date.parse(candidate?.timestamp)) || !/^[a-f0-9]{40}$/.test(candidate?.revision) || !profiles.includes(profile) || !semanticVersion.test(candidate?.version) || image?.file !== name2 || image?.prefix !== `candidates/${candidate.revision}/${profile}` || !positive(image?.bytes) || !sha256.test(image?.sha256) || !positive(image?.raw_bytes) || !sha256.test(image?.raw_sha256)) {
3534
+ throw new Error("Invalid Boo candidate metadata.");
3556
3535
  }
3557
- }
3558
- return candidates;
3536
+ return {
3537
+ run: candidate.number,
3538
+ version: candidate.version,
3539
+ revision: candidate.revision,
3540
+ timestamp: new Date(candidate.timestamp).toISOString(),
3541
+ candidate: { number: candidate.number },
3542
+ images: [{
3543
+ profile,
3544
+ id: candidate.number,
3545
+ name: name2,
3546
+ bytes: image.bytes,
3547
+ digest: image.sha256,
3548
+ cacheKind: "raw.zst",
3549
+ url: `${releaseOrigin}/${image.prefix}/${name2}`,
3550
+ rawBytes: image.raw_bytes,
3551
+ rawDigest: image.raw_sha256
3552
+ }]
3553
+ };
3554
+ });
3555
+ }
3556
+ async function discoverCandidates(signal) {
3557
+ return candidateCatalog(JSON.parse(await command([
3558
+ "curl",
3559
+ "--fail",
3560
+ "--silent",
3561
+ "--show-error",
3562
+ "--proto",
3563
+ "=https",
3564
+ "--header",
3565
+ "Cache-Control: no-cache",
3566
+ `${releaseOrigin}/candidates/index.json`
3567
+ ], signal, { limit: 1024 ** 2 })));
3559
3568
  }
3560
3569
  var FlashBackend = class {
3561
3570
  constructor(demo2) {
@@ -3581,11 +3590,11 @@ var FlashBackend = class {
3581
3590
  if (this.demo) return "Demo only: no cached images or USB contents were changed.";
3582
3591
  return clearCachedImages(signal);
3583
3592
  }
3584
- dependencies(includeGitHub = false) {
3585
- if (!this.demo) return this.requirePlatform().dependencies(includeGitHub);
3593
+ dependencies() {
3594
+ if (!this.demo) return this.requirePlatform().dependencies();
3586
3595
  const setup = this.demo.startsWith("setup") || this.demo === "no-homebrew";
3587
3596
  return {
3588
- missing: !setup || this.demoInstalled ? [] : this.demo === "setup-gh" ? includeGitHub ? ["gh"] : [] : this.demo === "setup-zstd" ? ["zstd"] : includeGitHub ? ["gh", "zstd"] : ["zstd"],
3597
+ missing: !setup || this.demoInstalled ? [] : ["zstd"],
3589
3598
  installer: this.demo === "no-homebrew" ? null : "Homebrew",
3590
3599
  guidance: "Demo dependency guidance."
3591
3600
  };
@@ -3608,7 +3617,7 @@ var FlashBackend = class {
3608
3617
  async catalog(signal) {
3609
3618
  if (!this.demo) return discoverImages(signal);
3610
3619
  await delay(350, void 0, { signal });
3611
- return { run: 149, version: "0.1.0+149", revision: "9b7574859120add5a1a478bc7923aeb1629be4ba", timestamp: "2026-08-28T14:23:45Z", images: profiles.map((profile, index) => ({
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) => ({
3612
3621
  profile,
3613
3622
  id: index,
3614
3623
  name: `demo-${profile}`,
@@ -3621,9 +3630,9 @@ var FlashBackend = class {
3621
3630
  const catalog = await this.catalog(signal);
3622
3631
  return this.demo === "empty" ? [] : [{
3623
3632
  ...catalog,
3624
- timestamp: "2026-08-29T01:02:03Z",
3633
+ timestamp: new Date(Date.now() - 5 * 60 * 1e3).toISOString(),
3625
3634
  images: [catalog.images[0]],
3626
- candidate: { number: 1, title: "Simulated candidate" }
3635
+ candidate: { number: 1 }
3627
3636
  }];
3628
3637
  }
3629
3638
  async disks(signal, staging = tmpdir4(), unmounted) {
@@ -3661,18 +3670,14 @@ var FlashBackend = class {
3661
3670
  if (process.getuid?.() === 0) throw new Error(`Run Boo Flash on ${platform3.id === "macos" ? "macOS" : "Linux"} as your normal user, not with sudo.`);
3662
3671
  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.");
3663
3672
  if (catalog.candidate) {
3664
- if (!positive(catalog.run) || !/^[a-f0-9]{40}$/.test(catalog.revision) || image.cacheKind || image.name !== `boo-${image.profile}-candidate-${catalog.revision}`) throw new Error("Invalid candidate selection.");
3665
- const artifact = JSON.parse(await command(["gh", "api", "--hostname", "github.com", `repos/${repository}/actions/artifacts/${image.id}`], signal));
3666
- if (artifact.id !== image.id || artifact.name !== image.name || artifact.workflow_run?.id !== catalog.run || artifact.expired !== false || !(Date.parse(artifact.expires_at) > Date.now()) || artifact.size_in_bytes !== image.bytes || artifact.digest !== `sha256:${image.digest}`) {
3667
- throw new Error("Selected candidate artifact changed or expired. Refresh Candidates. No disk was written.");
3668
- }
3673
+ if (!positive(catalog.run) || !/^[a-f0-9]{40}$/.test(catalog.revision) || image.id !== catalog.run || image.cacheKind !== "raw.zst" || image.name !== `boo-${catalog.version}-candidate-${catalog.revision.slice(0, 12)}-x86_64-${image.profile}.raw.zst` || image.url !== `${releaseOrigin}/candidates/${catalog.revision}/${image.profile}/${image.name}` || !positive(image.rawBytes) || !sha256.test(image.rawDigest ?? "")) throw new Error("Invalid candidate selection.");
3669
3674
  } else {
3670
3675
  const build = Number(catalog.version?.slice(catalog.version.lastIndexOf("+") + 1));
3671
3676
  const name2 = `boo-${catalog.version}-x86_64-${image.profile}.raw.zst`;
3672
3677
  if (!releaseVersion.test(catalog.version ?? "") || !positive(build) || catalog.run !== build || image.id !== build || !/^[a-f0-9]{40}$/.test(catalog.revision) || image.name !== name2 || image.cacheKind !== "raw.zst" || image.url !== `${releaseOrigin}/releases/${catalog.version}/${name2}` || !positive(image.rawBytes) || !sha256.test(image.rawDigest ?? "")) throw new Error("Invalid Boo release selection.");
3673
3678
  }
3674
3679
  const staging = await mkdtemp(join5(tmpdir4(), "boo-flash-"));
3675
- const payload = join5(staging, catalog.candidate ? "image.zip" : "image.raw.zst");
3680
+ const payload = join5(staging, "image.raw.zst");
3676
3681
  let unretained = false;
3677
3682
  let destructive = false;
3678
3683
  try {
@@ -3680,17 +3685,17 @@ var FlashBackend = class {
3680
3685
  let count = 0;
3681
3686
  if (!await reuseArchive(image, payload, signal, (count2) => update({
3682
3687
  stage: "Using cached image",
3683
- detail: `Verifying cached ${catalog.candidate ? "GitHub ZIP" : `Boo ${catalog.version} image`} size and SHA-256; no download.`,
3688
+ detail: `Verifying cached ${catalog.candidate ? "Boo candidate" : `Boo ${catalog.version} image`} size and SHA-256; no download.`,
3684
3689
  bytes: count2,
3685
3690
  total: image.bytes
3686
3691
  }))) {
3687
3692
  const payloadFile = await open2(payload, "wx", 384);
3688
3693
  const payloadHash = createHash2("sha256");
3689
3694
  const started = performance.now();
3690
- const detail = catalog.candidate ? "Selected candidate artifact only; authenticated with GitHub." : `Boo ${catalog.version} from images.os.boo.`;
3695
+ const detail = catalog.candidate ? "Selected candidate from images.os.boo." : `Boo ${catalog.version} from images.os.boo.`;
3691
3696
  update({ stage: "Downloading", detail, bytes: 0, total: image.bytes });
3692
3697
  try {
3693
- const argv = catalog.candidate ? ["gh", "api", "--hostname", "github.com", `repos/${repository}/actions/artifacts/${image.id}/zip`] : ["curl", "--fail", "--silent", "--show-error", "--proto", "=https", image.url];
3698
+ const argv = ["curl", "--fail", "--silent", "--show-error", "--proto", "=https", image.url];
3694
3699
  await command(argv, signal, {
3695
3700
  limit: image.bytes,
3696
3701
  consume: async (chunk) => {
@@ -3710,60 +3715,17 @@ var FlashBackend = class {
3710
3715
  await payloadFile.close();
3711
3716
  }
3712
3717
  if (count !== image.bytes || payloadHash.digest("hex") !== image.digest) {
3713
- throw new Error(`${catalog.candidate ? "GitHub ZIP" : "Release image"} size or SHA-256 mismatch. No disk was written.`);
3718
+ throw new Error(`${catalog.candidate ? "Candidate" : "Release"} image size or SHA-256 mismatch. No disk was written.`);
3714
3719
  }
3715
3720
  unretained = true;
3716
3721
  await publishArchive(image, payload, signal);
3717
3722
  unretained = false;
3718
3723
  }
3719
3724
  signal.throwIfAborted();
3720
- let compressed = payload;
3721
- let rawBytes = image.rawBytes;
3722
- let rawDigest = image.rawDigest;
3723
- if (catalog.candidate) {
3724
- update({ stage: "Verifying", detail: "Checking GitHub ZIP digest, build identity and image checksums." });
3725
- const names = (await command(["unzip", "-Z1", payload], signal)).trim().split("\n");
3726
- for (const name2 of ["build-info.json", "SHA256SUMS", "SHA256SUMS.raw"]) {
3727
- if (names.filter((n) => n === name2).length !== 1) throw new Error(`Archive is missing a unique ${name2}.`);
3728
- }
3729
- const extractText = (name2) => command(["unzip", "-p", payload, name2], signal, { limit: 1024 ** 2 });
3730
- const metadata = JSON.parse(await extractText("build-info.json"));
3731
- const basename2 = `boo-${image.profile}-x86_64.raw.zst`;
3732
- if (metadata.semantic_version !== void 0 && (!semanticVersion.test(metadata.semantic_version) || metadata.build_number !== null || metadata.version !== metadata.semantic_version)) {
3733
- throw new Error("Build metadata has an invalid candidate image version.");
3734
- }
3735
- if (metadata.image !== basename2 || names.filter((name2) => name2 === basename2).length !== 1 || metadata.schema !== 1 || !repositoryIdentities.has(metadata.repository) || metadata.revision !== catalog.revision || metadata.variant !== image.profile || metadata.source_state !== "clean" || !positive(metadata.compressed_bytes) || metadata.compressed_bytes > image.bytes || !positive(metadata.raw_apparent_bytes) || !sha256.test(metadata.compressed_sha256) || !sha256.test(metadata.raw_sha256)) {
3736
- throw new Error("Build metadata does not match the selected candidate.");
3737
- }
3738
- if (metadata.candidate?.resolved_sha !== catalog.revision || metadata.candidate?.profile !== image.profile || metadata.candidate?.qualification !== "build-only" || typeof metadata.candidate?.source_ref !== "string" || !metadata.candidate.source_ref.trim()) {
3739
- throw new Error("Candidate source metadata does not match the selected artifact.");
3740
- }
3741
- if ((await extractText("SHA256SUMS")).trim() !== `${metadata.compressed_sha256} ${basename2}` || (await extractText("SHA256SUMS.raw")).trim() !== `${metadata.raw_sha256} ${basename2.slice(0, -4)}`) {
3742
- throw new Error("Image checksum manifests disagree with build metadata.");
3743
- }
3744
- compressed = join5(staging, basename2);
3745
- const file = await open2(compressed, "wx", 384);
3746
- const hash = createHash2("sha256");
3747
- count = 0;
3748
- try {
3749
- await command(["unzip", "-p", payload, basename2], signal, {
3750
- limit: metadata.compressed_bytes,
3751
- consume: async (chunk) => {
3752
- hash.update(chunk);
3753
- await file.writeFile(chunk);
3754
- count += chunk.length;
3755
- update({ stage: "Verifying", detail: "Extracting only the selected image; checking compressed SHA-256.", bytes: count, total: metadata.compressed_bytes });
3756
- }
3757
- });
3758
- } finally {
3759
- await file.close();
3760
- }
3761
- if (count !== metadata.compressed_bytes || hash.digest("hex") !== metadata.compressed_sha256) throw new Error("Compressed image size or SHA-256 mismatch.");
3762
- rawBytes = metadata.raw_apparent_bytes;
3763
- rawDigest = metadata.raw_sha256;
3764
- } else {
3765
- update({ stage: "Verifying", detail: `Boo ${catalog.version} release metadata and compressed SHA-256 verified.` });
3766
- }
3725
+ const compressed = payload;
3726
+ const rawBytes = image.rawBytes;
3727
+ const rawDigest = image.rawDigest;
3728
+ update({ stage: "Verifying", detail: `${catalog.candidate ? "Boo candidate" : `Boo ${catalog.version}`} metadata and compressed SHA-256 verified.` });
3767
3729
  if (!positive(rawBytes) || !sha256.test(rawDigest ?? "")) throw new Error("Image raw-stream metadata is invalid.");
3768
3730
  if (rawBytes > disk.bytes) throw new Error(`Image needs ${bytes(rawBytes)}; the selected USB is too small.`);
3769
3731
  const revalidate = async (unmounted = false) => {
@@ -3860,6 +3822,7 @@ function App(props) {
3860
3822
  detail: ""
3861
3823
  });
3862
3824
  const [frame, setFrame] = createSignal(0);
3825
+ const [now, setNow] = createSignal(Date.now());
3863
3826
  let controller = new AbortController();
3864
3827
  let pending = Promise.resolve();
3865
3828
  let closing = false;
@@ -3894,7 +3857,7 @@ function App(props) {
3894
3857
  if (!closing) {
3895
3858
  const setup = screen() === "installing";
3896
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.");
3897
- if (setup) setDependencies(props.backend.dependencies(setupCandidates()));
3860
+ if (setup) setDependencies(props.backend.dependencies());
3898
3861
  setScreen(setup ? "setup" : "error");
3899
3862
  setCursor(0);
3900
3863
  }
@@ -3929,7 +3892,7 @@ function App(props) {
3929
3892
  setCursor(0);
3930
3893
  setScreen("candidates");
3931
3894
  operation(async (signal) => {
3932
- const state = props.backend.dependencies(true);
3895
+ const state = props.backend.dependencies();
3933
3896
  if (state.missing.length) {
3934
3897
  setDependencies(state);
3935
3898
  setScreen("setup");
@@ -3961,7 +3924,11 @@ function App(props) {
3961
3924
  await pending;
3962
3925
  };
3963
3926
  props.registerStop(stop);
3964
- onMount(refresh);
3927
+ onMount(() => {
3928
+ refresh();
3929
+ const timer = setInterval(() => setNow(Date.now()), 60 * 1e3);
3930
+ onCleanup(() => clearInterval(timer));
3931
+ });
3965
3932
  const activate = () => {
3966
3933
  if (busy() || !visible()) return;
3967
3934
  if (screen() === "setup") {
@@ -4104,10 +4071,9 @@ function App(props) {
4104
4071
  return detail && (!tight() || detailWhenTight);
4105
4072
  },
4106
4073
  get children() {
4107
- var _el$3 = createElement("text"), _el$4 = createTextNode(` `);
4108
- insertNode(_el$3, _el$4);
4074
+ var _el$3 = createElement("text");
4109
4075
  setProp(_el$3, "wrapMode", "none");
4110
- insert(_el$3, detail, null);
4076
+ insert(_el$3, ` ${detail}`);
4111
4077
  effect((_$p) => setProp(_el$3, "fg", palette.muted, _$p));
4112
4078
  return _el$3;
4113
4079
  }
@@ -4128,43 +4094,43 @@ function App(props) {
4128
4094
  return _el$;
4129
4095
  })();
4130
4096
  return (() => {
4131
- var _el$5 = createElement("box"), _el$6 = createElement("box"), _el$7 = createElement("box"), _el$8 = createElement("text"), _el$0 = createElement("text"), _el$1 = createElement("box"), _el$10 = createElement("box"), _el$88 = createElement("text");
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");
4098
+ insertNode(_el$4, _el$5);
4099
+ setProp(_el$4, "width", "100%");
4100
+ setProp(_el$4, "height", "100%");
4101
+ setProp(_el$4, "justifyContent", "center");
4102
+ setProp(_el$4, "alignItems", "center");
4132
4103
  insertNode(_el$5, _el$6);
4133
- setProp(_el$5, "width", "100%");
4134
- setProp(_el$5, "height", "100%");
4135
- setProp(_el$5, "justifyContent", "center");
4136
- setProp(_el$5, "alignItems", "center");
4104
+ insertNode(_el$5, _el$0);
4105
+ insertNode(_el$5, _el$1);
4106
+ insertNode(_el$5, _el$87);
4107
+ setProp(_el$5, "border", true);
4108
+ setProp(_el$5, "borderStyle", "single");
4109
+ setProp(_el$5, "flexDirection", "column");
4110
+ setProp(_el$5, "paddingX", 1);
4137
4111
  insertNode(_el$6, _el$7);
4138
- insertNode(_el$6, _el$1);
4139
- insertNode(_el$6, _el$10);
4140
- insertNode(_el$6, _el$88);
4141
- setProp(_el$6, "border", true);
4142
- setProp(_el$6, "borderStyle", "single");
4143
- setProp(_el$6, "flexDirection", "column");
4144
- setProp(_el$6, "paddingX", 1);
4145
- insertNode(_el$7, _el$8);
4146
- insertNode(_el$7, _el$0);
4147
- setProp(_el$7, "height", 1);
4148
- setProp(_el$7, "flexDirection", "row");
4149
- setProp(_el$7, "justifyContent", "space-between");
4150
- setProp(_el$7, "flexShrink", 0);
4151
- insertNode(_el$8, createTextNode(`BOO FLASH`));
4152
- insert(_el$0, () => props.backend.platformLabel);
4153
- setProp(_el$1, "height", 1);
4154
- setProp(_el$1, "flexShrink", 0);
4155
- setProp(_el$10, "flexGrow", 1);
4156
- setProp(_el$10, "minHeight", 0);
4157
- setProp(_el$10, "overflow", "hidden");
4158
- insert(_el$10, createComponent2(Show, {
4112
+ insertNode(_el$6, _el$9);
4113
+ setProp(_el$6, "height", 1);
4114
+ setProp(_el$6, "flexDirection", "row");
4115
+ setProp(_el$6, "justifyContent", "space-between");
4116
+ setProp(_el$6, "flexShrink", 0);
4117
+ insertNode(_el$7, createTextNode(`BOO FLASH`));
4118
+ insert(_el$9, () => props.backend.platformLabel);
4119
+ setProp(_el$0, "height", 1);
4120
+ setProp(_el$0, "flexShrink", 0);
4121
+ setProp(_el$1, "flexGrow", 1);
4122
+ setProp(_el$1, "minHeight", 0);
4123
+ setProp(_el$1, "overflow", "hidden");
4124
+ insert(_el$1, createComponent2(Show, {
4159
4125
  get when() {
4160
4126
  return visible();
4161
4127
  },
4162
4128
  get fallback() {
4163
4129
  return (() => {
4164
- var _el$89 = createElement("text");
4165
- insertNode(_el$89, createTextNode(`Enlarge the terminal to show the full choices and erase warning. Q quits.`));
4166
- effect((_$p) => setProp(_el$89, "fg", palette.warning, _$p));
4167
- return _el$89;
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;
4168
4134
  })();
4169
4135
  },
4170
4136
  get children() {
@@ -4174,41 +4140,43 @@ function App(props) {
4174
4140
  },
4175
4141
  get children() {
4176
4142
  return [(() => {
4177
- var _el$11 = createElement("text");
4178
- insertNode(_el$11, createTextNode(`Choose the target computer's GPU`));
4143
+ var _el$10 = createElement("text");
4144
+ insertNode(_el$10, createTextNode(`Choose the target computer's GPU`));
4179
4145
  effect((_p$) => {
4180
4146
  var _v$5 = palette.foreground, _v$6 = TextAttributes2.BOLD;
4181
- _v$5 !== _p$.e && (_p$.e = setProp(_el$11, "fg", _v$5, _p$.e));
4182
- _v$6 !== _p$.t && (_p$.t = setProp(_el$11, "attributes", _v$6, _p$.t));
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));
4183
4149
  return _p$;
4184
4150
  }, {
4185
4151
  e: void 0,
4186
4152
  t: void 0
4187
4153
  });
4188
- return _el$11;
4154
+ return _el$10;
4189
4155
  })(), (() => {
4190
- var _el$13 = createElement("text");
4191
- insert(_el$13, (() => {
4156
+ var _el$12 = createElement("text");
4157
+ insert(_el$12, (() => {
4192
4158
  var _c$ = memo2(() => !!loading());
4193
- return () => _c$() ? `${spinner()} Finding latest Boo release...` : memo2(() => !!catalog())() ? `Boo ${catalog().version} / ${catalog().revision.slice(0, 7)} / ${localTimestamp(catalog().timestamp)}` : "Dependencies needed. Enter to set up.";
4159
+ 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.";
4194
4160
  })());
4195
- effect((_$p) => setProp(_el$13, "fg", palette.muted, _$p));
4196
- return _el$13;
4161
+ effect((_$p) => setProp(_el$12, "fg", palette.muted, _$p));
4162
+ return _el$12;
4197
4163
  })(), (() => {
4198
- var _el$14 = createElement("box");
4199
- setProp(_el$14, "gap", 0);
4200
- insert(_el$14, createComponent2(For, {
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, {
4201
4169
  each: profiles,
4202
4170
  children: (profile, index) => row(profile.toUpperCase(), profile === "nvidia" ? "NVIDIA graphics" : `${profile === "intel" ? "Intel" : "AMD Radeon"} graphics`, index())
4203
4171
  }), null);
4204
- insert(_el$14, () => row("Candidates", "", 3), null);
4205
- insert(_el$14, () => row("Clear cached images", "", 4), null);
4206
- return _el$14;
4172
+ insert(_el$13, () => row("Candidates", "", 3), null);
4173
+ insert(_el$13, () => row("Clear cached images", "", 4), null);
4174
+ return _el$13;
4207
4175
  })(), (() => {
4208
- var _el$15 = createElement("text");
4209
- insertNode(_el$15, createTextNode(`All images support Intel and AMD x86_64 CPUs.`));
4210
- effect((_$p) => setProp(_el$15, "fg", palette.muted, _$p));
4211
- return _el$15;
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));
4179
+ return _el$14;
4212
4180
  })()];
4213
4181
  }
4214
4182
  }), createComponent2(Show, {
@@ -4217,34 +4185,34 @@ function App(props) {
4217
4185
  },
4218
4186
  get children() {
4219
4187
  return [(() => {
4220
- var _el$17 = createElement("text");
4221
- insertNode(_el$17, createTextNode(`Clear cached images?`));
4188
+ var _el$16 = createElement("text");
4189
+ insertNode(_el$16, createTextNode(`Clear cached images?`));
4222
4190
  effect((_p$) => {
4223
4191
  var _v$7 = palette.warning, _v$8 = TextAttributes2.BOLD;
4224
- _v$7 !== _p$.e && (_p$.e = setProp(_el$17, "fg", _v$7, _p$.e));
4225
- _v$8 !== _p$.t && (_p$.t = setProp(_el$17, "attributes", _v$8, _p$.t));
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));
4226
4194
  return _p$;
4227
4195
  }, {
4228
4196
  e: void 0,
4229
4197
  t: void 0
4230
4198
  });
4231
- return _el$17;
4199
+ return _el$16;
4232
4200
  })(), (() => {
4233
- var _el$19 = createElement("text");
4234
- insertNode(_el$19, createTextNode(`Removes downloaded archives only, NOT USB contents. Active flashes are unaffected.`));
4235
- effect((_$p) => setProp(_el$19, "fg", palette.foreground, _$p));
4236
- return _el$19;
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;
4237
4205
  })(), (() => {
4238
- var _el$21 = createElement("text");
4239
- insertNode(_el$21, createTextNode(`Images will download again when needed. Pending downloads may still finish and be cached.`));
4240
- effect((_$p) => setProp(_el$21, "fg", palette.muted, _$p));
4241
- return _el$21;
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;
4242
4210
  })(), (() => {
4243
- var _el$23 = createElement("box");
4244
- insert(_el$23, () => row("Go back", "", 0), null);
4245
- insert(_el$23, () => row(loading() ? "Clearing..." : "Clear cached images", "", 1, true), null);
4246
- effect((_$p) => setProp(_el$23, "gap", tight() ? 0 : 1, _$p));
4247
- return _el$23;
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;
4248
4216
  })()];
4249
4217
  }
4250
4218
  }), createComponent2(Show, {
@@ -4253,23 +4221,23 @@ function App(props) {
4253
4221
  },
4254
4222
  get children() {
4255
4223
  return [(() => {
4256
- var _el$24 = createElement("text");
4257
- insertNode(_el$24, createTextNode(`Cache cleared`));
4224
+ var _el$23 = createElement("text");
4225
+ insertNode(_el$23, createTextNode(`Cache cleared`));
4258
4226
  effect((_p$) => {
4259
4227
  var _v$9 = palette.success, _v$0 = TextAttributes2.BOLD;
4260
- _v$9 !== _p$.e && (_p$.e = setProp(_el$24, "fg", _v$9, _p$.e));
4261
- _v$0 !== _p$.t && (_p$.t = setProp(_el$24, "attributes", _v$0, _p$.t));
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));
4262
4230
  return _p$;
4263
4231
  }, {
4264
4232
  e: void 0,
4265
4233
  t: void 0
4266
4234
  });
4267
- return _el$24;
4235
+ return _el$23;
4268
4236
  })(), (() => {
4269
- var _el$26 = createElement("text");
4270
- insert(_el$26, notice);
4271
- effect((_$p) => setProp(_el$26, "fg", palette.foreground, _$p));
4272
- return _el$26;
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;
4273
4241
  })(), memo2(() => row("Go back", "", 0))];
4274
4242
  }
4275
4243
  }), createComponent2(Show, {
@@ -4278,34 +4246,34 @@ function App(props) {
4278
4246
  },
4279
4247
  get children() {
4280
4248
  return [(() => {
4281
- var _el$27 = createElement("text");
4282
- insertNode(_el$27, createTextNode(`Candidates`));
4249
+ var _el$26 = createElement("text");
4250
+ insertNode(_el$26, createTextNode(`Candidates`));
4283
4251
  effect((_p$) => {
4284
4252
  var _v$1 = palette.foreground, _v$10 = TextAttributes2.BOLD;
4285
- _v$1 !== _p$.e && (_p$.e = setProp(_el$27, "fg", _v$1, _p$.e));
4286
- _v$10 !== _p$.t && (_p$.t = setProp(_el$27, "attributes", _v$10, _p$.t));
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));
4287
4255
  return _p$;
4288
4256
  }, {
4289
4257
  e: void 0,
4290
4258
  t: void 0
4291
4259
  });
4292
- return _el$27;
4260
+ return _el$26;
4293
4261
  })(), (() => {
4294
- var _el$29 = createElement("text");
4295
- insertNode(_el$29, createTextNode(`Build-only; not boot/install/hardware qualified.`));
4296
- effect((_$p) => setProp(_el$29, "fg", palette.warning, _$p));
4297
- return _el$29;
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;
4298
4266
  })(), createComponent2(Show, {
4299
4267
  get when() {
4300
4268
  return !loading();
4301
4269
  },
4302
4270
  get fallback() {
4303
4271
  return (() => {
4304
- var _el$91 = createElement("text"), _el$92 = createTextNode(` Finding completed candidates...`);
4305
- insertNode(_el$91, _el$92);
4306
- insert(_el$91, spinner, _el$92);
4307
- effect((_$p) => setProp(_el$91, "fg", palette.muted, _$p));
4308
- return _el$91;
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;
4309
4277
  })();
4310
4278
  },
4311
4279
  get children() {
@@ -4315,31 +4283,31 @@ function App(props) {
4315
4283
  },
4316
4284
  get fallback() {
4317
4285
  return [(() => {
4318
- var _el$93 = createElement("text");
4319
- insertNode(_el$93, createTextNode(`No completed candidates available`));
4320
- effect((_$p) => setProp(_el$93, "fg", palette.muted, _$p));
4321
- return _el$93;
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;
4322
4290
  })(), memo2(() => row("Go back", "", 0))];
4323
4291
  },
4324
4292
  get children() {
4325
4293
  return [(() => {
4326
- var _el$31 = createElement("box");
4327
- setProp(_el$31, "gap", 0);
4328
- insert(_el$31, createComponent2(For, {
4294
+ var _el$30 = createElement("box");
4295
+ setProp(_el$30, "gap", 0);
4296
+ insert(_el$30, createComponent2(For, {
4329
4297
  get each() {
4330
4298
  return candidates().slice(Math.max(0, cursor() - 2), Math.max(3, cursor() + 1));
4331
4299
  },
4332
- children: (c, index) => row(`${c.images[0].profile.toUpperCase()} ${c.revision.slice(0, 7)} #${c.candidate.number}`, `${localTimestamp(c.timestamp)} ${c.candidate.title}`, index() + Math.max(0, cursor() - 2), false, true)
4300
+ 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)
4333
4301
  }));
4334
- return _el$31;
4302
+ return _el$30;
4335
4303
  })(), (() => {
4336
- var _el$32 = createElement("text"), _el$33 = createTextNode(` of `), _el$34 = createTextNode(` candidates / Enter to choose`);
4337
- insertNode(_el$32, _el$33);
4338
- insertNode(_el$32, _el$34);
4339
- insert(_el$32, () => cursor() + 1, _el$33);
4340
- insert(_el$32, () => candidates().length, _el$34);
4341
- effect((_$p) => setProp(_el$32, "fg", palette.muted, _$p));
4342
- return _el$32;
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;
4343
4311
  })()];
4344
4312
  }
4345
4313
  });
@@ -4352,71 +4320,71 @@ function App(props) {
4352
4320
  },
4353
4321
  get children() {
4354
4322
  return [(() => {
4355
- var _el$35 = createElement("text");
4356
- insertNode(_el$35, createTextNode(`Set up required tools`));
4323
+ var _el$34 = createElement("text");
4324
+ insertNode(_el$34, createTextNode(`Set up required tools`));
4357
4325
  effect((_p$) => {
4358
4326
  var _v$11 = palette.accent, _v$12 = TextAttributes2.BOLD;
4359
- _v$11 !== _p$.e && (_p$.e = setProp(_el$35, "fg", _v$11, _p$.e));
4360
- _v$12 !== _p$.t && (_p$.t = setProp(_el$35, "attributes", _v$12, _p$.t));
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));
4361
4329
  return _p$;
4362
4330
  }, {
4363
4331
  e: void 0,
4364
4332
  t: void 0
4365
4333
  });
4366
- return _el$35;
4334
+ return _el$34;
4367
4335
  })(), (() => {
4368
- var _el$37 = createElement("text"), _el$38 = createTextNode(`Missing: `);
4369
- insertNode(_el$37, _el$38);
4370
- insert(_el$37, () => dependencies3().missing.join(", "), null);
4371
- effect((_$p) => setProp(_el$37, "fg", palette.foreground, _$p));
4372
- return _el$37;
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;
4373
4341
  })(), createComponent2(Show, {
4374
4342
  get when() {
4375
4343
  return !error();
4376
4344
  },
4377
4345
  get fallback() {
4378
4346
  return (() => {
4379
- var _el$95 = createElement("text");
4380
- insert(_el$95, error);
4381
- effect((_$p) => setProp(_el$95, "fg", palette.warning, _$p));
4382
- return _el$95;
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;
4383
4351
  })();
4384
4352
  },
4385
4353
  get children() {
4386
- var _el$39 = createElement("text");
4387
- insert(_el$39, (() => {
4354
+ var _el$38 = createElement("text");
4355
+ insert(_el$38, (() => {
4388
4356
  var _c$2 = memo2(() => !!dependencies3().installer);
4389
4357
  return () => _c$2() ? `${dependencies3().installer} will install ${dependencies3().missing.join(" and ")} and required dependencies, then continue.` : dependencies3().guidance;
4390
4358
  })());
4391
- effect((_$p) => setProp(_el$39, "fg", palette.muted, _$p));
4392
- return _el$39;
4359
+ effect((_$p) => setProp(_el$38, "fg", palette.muted, _$p));
4360
+ return _el$38;
4393
4361
  }
4394
4362
  }), createComponent2(Show, {
4395
4363
  get when() {
4396
4364
  return !tight();
4397
4365
  },
4398
4366
  get children() {
4399
- var _el$40 = createElement("text");
4400
- insert(_el$40, () => dependencies3().installer ? "Uses the ordinary terminal. Ctrl-C cancels and quits." : "Boo Flash will not change system packages on this platform.");
4401
- effect((_$p) => setProp(_el$40, "fg", palette.muted, _$p));
4402
- return _el$40;
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;
4403
4371
  }
4404
4372
  }), createComponent2(Show, {
4405
4373
  get when() {
4406
4374
  return props.backend.demo;
4407
4375
  },
4408
4376
  get children() {
4409
- var _el$41 = createElement("text");
4410
- insertNode(_el$41, createTextNode(`Setup simulation; no software installed.`));
4411
- effect((_$p) => setProp(_el$41, "fg", palette.warning, _$p));
4412
- return _el$41;
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;
4413
4381
  }
4414
4382
  }), (() => {
4415
- var _el$43 = createElement("box");
4416
- insert(_el$43, () => row("Go back", "", 0), null);
4417
- insert(_el$43, () => row(dependencies3().installer ? `Install ${dependencies3().missing.join(" + ")}` : "Refresh", "", 1), null);
4418
- effect((_$p) => setProp(_el$43, "gap", tight() ? 0 : 1, _$p));
4419
- return _el$43;
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;
4420
4388
  })()];
4421
4389
  }
4422
4390
  }), createComponent2(Show, {
@@ -4425,42 +4393,42 @@ function App(props) {
4425
4393
  },
4426
4394
  get children() {
4427
4395
  return [(() => {
4428
- var _el$44 = createElement("text"), _el$45 = createTextNode(` `);
4429
- insertNode(_el$44, _el$45);
4430
- insert(_el$44, spinner, _el$45);
4431
- insert(_el$44, () => stopping() ? "Waiting for setup to stop..." : "Installing required tools", null);
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);
4432
4400
  effect((_p$) => {
4433
4401
  var _v$13 = palette.accent, _v$14 = TextAttributes2.BOLD;
4434
- _v$13 !== _p$.e && (_p$.e = setProp(_el$44, "fg", _v$13, _p$.e));
4435
- _v$14 !== _p$.t && (_p$.t = setProp(_el$44, "attributes", _v$14, _p$.t));
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));
4436
4404
  return _p$;
4437
4405
  }, {
4438
4406
  e: void 0,
4439
4407
  t: void 0
4440
4408
  });
4441
- return _el$44;
4409
+ return _el$43;
4442
4410
  })(), (() => {
4443
- var _el$46 = createElement("text"), _el$47 = createTextNode(` via `);
4444
- insertNode(_el$46, _el$47);
4445
- insert(_el$46, () => dependencies3().missing.join(" + "), _el$47);
4446
- insert(_el$46, () => dependencies3().installer, null);
4447
- effect((_$p) => setProp(_el$46, "fg", palette.foreground, _$p));
4448
- return _el$46;
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;
4449
4417
  })(), (() => {
4450
- var _el$48 = createElement("text"), _el$49 = createTextNode(` uses the ordinary terminal. Ctrl-C cancels and quits; wait for cleanup.`);
4451
- insertNode(_el$48, _el$49);
4452
- insert(_el$48, () => dependencies3().installer, _el$49);
4453
- effect((_$p) => setProp(_el$48, "fg", palette.muted, _$p));
4454
- return _el$48;
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;
4455
4423
  })(), createComponent2(Show, {
4456
4424
  get when() {
4457
4425
  return props.backend.demo;
4458
4426
  },
4459
4427
  get children() {
4460
- var _el$50 = createElement("text");
4461
- insertNode(_el$50, createTextNode(`Setup simulation; no software installed.`));
4462
- effect((_$p) => setProp(_el$50, "fg", palette.warning, _$p));
4463
- return _el$50;
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;
4464
4432
  }
4465
4433
  })];
4466
4434
  }
@@ -4470,26 +4438,26 @@ function App(props) {
4470
4438
  },
4471
4439
  get children() {
4472
4440
  return [(() => {
4473
- var _el$52 = createElement("text");
4474
- insertNode(_el$52, createTextNode(`Choose a USB drive`));
4441
+ var _el$51 = createElement("text");
4442
+ insertNode(_el$51, createTextNode(`Choose a USB drive`));
4475
4443
  effect((_p$) => {
4476
4444
  var _v$15 = palette.foreground, _v$16 = TextAttributes2.BOLD;
4477
- _v$15 !== _p$.e && (_p$.e = setProp(_el$52, "fg", _v$15, _p$.e));
4478
- _v$16 !== _p$.t && (_p$.t = setProp(_el$52, "attributes", _v$16, _p$.t));
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));
4479
4447
  return _p$;
4480
4448
  }, {
4481
4449
  e: void 0,
4482
4450
  t: void 0
4483
4451
  });
4484
- return _el$52;
4452
+ return _el$51;
4485
4453
  })(), (() => {
4486
- var _el$54 = createElement("text");
4487
- insert(_el$54, (() => {
4454
+ var _el$53 = createElement("text");
4455
+ insert(_el$53, (() => {
4488
4456
  var _c$3 = memo2(() => !!loading());
4489
4457
  return () => _c$3() ? `${spinner()} Checking disks and protected storage...` : "System, home and app storage are excluded.";
4490
4458
  })());
4491
- effect((_$p) => setProp(_el$54, "fg", palette.muted, _$p));
4492
- return _el$54;
4459
+ effect((_$p) => setProp(_el$53, "fg", palette.muted, _$p));
4460
+ return _el$53;
4493
4461
  })(), createComponent2(Show, {
4494
4462
  get when() {
4495
4463
  return !loading();
@@ -4501,31 +4469,31 @@ function App(props) {
4501
4469
  },
4502
4470
  get fallback() {
4503
4471
  return (() => {
4504
- var _el$96 = createElement("text");
4505
- insertNode(_el$96, createTextNode(`No eligible USB drives. Connect a writable external USB drive, then press R to refresh.`));
4506
- effect((_$p) => setProp(_el$96, "fg", palette.warning, _$p));
4507
- return _el$96;
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;
4508
4476
  })();
4509
4477
  },
4510
4478
  get children() {
4511
4479
  return [(() => {
4512
- var _el$55 = createElement("box");
4513
- setProp(_el$55, "gap", 0);
4514
- insert(_el$55, createComponent2(For, {
4480
+ var _el$54 = createElement("box");
4481
+ setProp(_el$54, "gap", 0);
4482
+ insert(_el$54, createComponent2(For, {
4515
4483
  get each() {
4516
4484
  return disks3().slice(Math.max(0, cursor() - 2), Math.max(3, cursor() + 1));
4517
4485
  },
4518
4486
  children: (d, index) => row(d.name, `${path(d)} / ${bytes(d.bytes)} / USB`, index() + Math.max(0, cursor() - 2))
4519
4487
  }));
4520
- return _el$55;
4488
+ return _el$54;
4521
4489
  })(), (() => {
4522
- var _el$56 = createElement("text");
4523
- insert(_el$56, (() => {
4490
+ var _el$55 = createElement("text");
4491
+ insert(_el$55, (() => {
4524
4492
  var _c$4 = memo2(() => cursor() < 0);
4525
4493
  return () => _c$4() ? "Use arrows to select a drive. Nothing is selected yet." : `${cursor() + 1} of ${disks3().length} drives / Enter to review`;
4526
4494
  })());
4527
- effect((_$p) => setProp(_el$56, "fg", palette.muted, _$p));
4528
- return _el$56;
4495
+ effect((_$p) => setProp(_el$55, "fg", palette.muted, _$p));
4496
+ return _el$55;
4529
4497
  })()];
4530
4498
  }
4531
4499
  });
@@ -4538,44 +4506,44 @@ function App(props) {
4538
4506
  },
4539
4507
  get children() {
4540
4508
  return [(() => {
4541
- var _el$57 = createElement("text");
4542
- insertNode(_el$57, createTextNode(`Erase this entire USB drive?`));
4509
+ var _el$56 = createElement("text");
4510
+ insertNode(_el$56, createTextNode(`Erase this entire USB drive?`));
4543
4511
  effect((_p$) => {
4544
4512
  var _v$17 = palette.warning, _v$18 = TextAttributes2.BOLD;
4545
- _v$17 !== _p$.e && (_p$.e = setProp(_el$57, "fg", _v$17, _p$.e));
4546
- _v$18 !== _p$.t && (_p$.t = setProp(_el$57, "attributes", _v$18, _p$.t));
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));
4547
4515
  return _p$;
4548
4516
  }, {
4549
4517
  e: void 0,
4550
4518
  t: void 0
4551
4519
  });
4552
- return _el$57;
4520
+ return _el$56;
4553
4521
  })(), (() => {
4554
- var _el$59 = createElement("box"), _el$60 = createElement("text"), _el$61 = createElement("text"), _el$62 = createElement("text"), _el$63 = createTextNode(` / `);
4555
- insertNode(_el$59, _el$60);
4556
- insertNode(_el$59, _el$61);
4557
- insertNode(_el$59, _el$62);
4558
- setProp(_el$59, "paddingX", 1);
4559
- setProp(_el$60, "height", 1);
4560
- setProp(_el$60, "wrapMode", "none");
4561
- insert(_el$60, () => disk()?.name);
4562
- insert(_el$61, (() => {
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, (() => {
4563
4531
  var _c$5 = memo2(() => !!disk());
4564
4532
  return () => _c$5() ? `${path(disk())} / ${bytes(disk().bytes)}` : "";
4565
4533
  })());
4566
- insertNode(_el$62, _el$63);
4567
- insert(_el$62, () => image()?.profile.toUpperCase(), _el$63);
4568
- insert(_el$62, (() => {
4534
+ insertNode(_el$61, _el$62);
4535
+ insert(_el$61, () => image()?.profile.toUpperCase(), _el$62);
4536
+ insert(_el$61, (() => {
4569
4537
  var _c$6 = memo2(() => !!catalog()?.candidate);
4570
4538
  return () => _c$6() ? `candidate (build-only) ${catalog()?.revision.slice(0, 7)}` : `Boo ${catalog()?.version}`;
4571
4539
  })(), null);
4572
4540
  effect((_p$) => {
4573
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;
4574
- _v$19 !== _p$.e && (_p$.e = setProp(_el$59, "backgroundColor", _v$19, _p$.e));
4575
- _v$20 !== _p$.t && (_p$.t = setProp(_el$60, "fg", _v$20, _p$.t));
4576
- _v$21 !== _p$.a && (_p$.a = setProp(_el$60, "attributes", _v$21, _p$.a));
4577
- _v$22 !== _p$.o && (_p$.o = setProp(_el$61, "fg", _v$22, _p$.o));
4578
- _v$23 !== _p$.i && (_p$.i = setProp(_el$62, "fg", _v$23, _p$.i));
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));
4579
4547
  return _p$;
4580
4548
  }, {
4581
4549
  e: void 0,
@@ -4584,18 +4552,18 @@ function App(props) {
4584
4552
  o: void 0,
4585
4553
  i: void 0
4586
4554
  });
4587
- return _el$59;
4555
+ return _el$58;
4588
4556
  })(), (() => {
4589
- var _el$64 = createElement("text");
4590
- insertNode(_el$64, createTextNode(`ALL data and partitions on this drive will be lost. Back up anything you need before continuing.`));
4591
- effect((_$p) => setProp(_el$64, "fg", palette.warning, _$p));
4592
- return _el$64;
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;
4593
4561
  })(), (() => {
4594
- var _el$66 = createElement("box");
4595
- insert(_el$66, () => row("Go back", "", 0), null);
4596
- insert(_el$66, () => row("Erase & flash", "", 1, true), null);
4597
- effect((_$p) => setProp(_el$66, "gap", tight() ? 0 : 1, _$p));
4598
- return _el$66;
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;
4599
4567
  })()];
4600
4568
  }
4601
4569
  }), createComponent2(Show, {
@@ -4604,108 +4572,108 @@ function App(props) {
4604
4572
  },
4605
4573
  get children() {
4606
4574
  return [(() => {
4607
- var _el$67 = createElement("text"), _el$68 = createTextNode(` `);
4608
- insertNode(_el$67, _el$68);
4609
- insert(_el$67, spinner, _el$68);
4610
- insert(_el$67, (() => {
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, (() => {
4611
4579
  var _c$7 = memo2(() => !!stopping());
4612
4580
  return () => _c$7() ? "Stopping safely..." : progress().stage;
4613
4581
  })(), null);
4614
4582
  effect((_p$) => {
4615
4583
  var _v$24 = palette.accent, _v$25 = TextAttributes2.BOLD;
4616
- _v$24 !== _p$.e && (_p$.e = setProp(_el$67, "fg", _v$24, _p$.e));
4617
- _v$25 !== _p$.t && (_p$.t = setProp(_el$67, "attributes", _v$25, _p$.t));
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));
4618
4586
  return _p$;
4619
4587
  }, {
4620
4588
  e: void 0,
4621
4589
  t: void 0
4622
4590
  });
4623
- return _el$67;
4591
+ return _el$66;
4624
4592
  })(), (() => {
4625
- var _el$69 = createElement("text"), _el$70 = createTextNode(` / `);
4626
- insertNode(_el$69, _el$70);
4627
- insert(_el$69, () => disk()?.name, _el$70);
4628
- insert(_el$69, () => image()?.profile.toUpperCase(), null);
4629
- effect((_$p) => setProp(_el$69, "fg", palette.foreground, _$p));
4630
- return _el$69;
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;
4631
4599
  })(), (() => {
4632
- var _el$71 = createElement("text");
4633
- insert(_el$71, (() => {
4600
+ var _el$70 = createElement("text");
4601
+ insert(_el$70, (() => {
4634
4602
  var _c$8 = memo2(() => !!stopping());
4635
4603
  return () => _c$8() ? "Waiting for all child processes to stop. Keep the USB connected." : progress().detail;
4636
4604
  })());
4637
- effect((_$p) => setProp(_el$71, "fg", palette.muted, _$p));
4638
- return _el$71;
4605
+ effect((_$p) => setProp(_el$70, "fg", palette.muted, _$p));
4606
+ return _el$70;
4639
4607
  })(), createComponent2(Show, {
4640
4608
  get when() {
4641
4609
  return percent() !== void 0;
4642
4610
  },
4643
4611
  get children() {
4644
4612
  return [(() => {
4645
- var _el$72 = createElement("box");
4646
- setProp(_el$72, "border", true);
4647
- setProp(_el$72, "height", 3);
4648
- insert(_el$72, createComponent2(Show, {
4613
+ var _el$71 = createElement("box");
4614
+ setProp(_el$71, "border", true);
4615
+ setProp(_el$71, "height", 3);
4616
+ insert(_el$71, createComponent2(Show, {
4649
4617
  get when() {
4650
4618
  return percent() > 0;
4651
4619
  },
4652
4620
  get children() {
4653
- var _el$73 = createElement("box");
4654
- setProp(_el$73, "height", 1);
4621
+ var _el$72 = createElement("box");
4622
+ setProp(_el$72, "height", 1);
4655
4623
  effect((_p$) => {
4656
4624
  var _v$26 = `${percent() ?? 0}%`, _v$27 = palette.accent;
4657
- _v$26 !== _p$.e && (_p$.e = setProp(_el$73, "width", _v$26, _p$.e));
4658
- _v$27 !== _p$.t && (_p$.t = setProp(_el$73, "backgroundColor", _v$27, _p$.t));
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));
4659
4627
  return _p$;
4660
4628
  }, {
4661
4629
  e: void 0,
4662
4630
  t: void 0
4663
4631
  });
4664
- return _el$73;
4632
+ return _el$72;
4665
4633
  }
4666
4634
  }));
4667
4635
  effect((_p$) => {
4668
4636
  var _v$28 = palette.accent, _v$29 = palette.panelAlt;
4669
- _v$28 !== _p$.e && (_p$.e = setProp(_el$72, "borderColor", _v$28, _p$.e));
4670
- _v$29 !== _p$.t && (_p$.t = setProp(_el$72, "backgroundColor", _v$29, _p$.t));
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));
4671
4639
  return _p$;
4672
4640
  }, {
4673
4641
  e: void 0,
4674
4642
  t: void 0
4675
4643
  });
4676
- return _el$72;
4644
+ return _el$71;
4677
4645
  })(), (() => {
4678
- var _el$74 = createElement("text"), _el$75 = createTextNode(`% `), _el$76 = createTextNode(` / `);
4679
- insertNode(_el$74, _el$75);
4680
- insertNode(_el$74, _el$76);
4681
- insert(_el$74, percent, _el$75);
4682
- insert(_el$74, () => bytes(progress().bytes ?? 0), _el$76);
4683
- insert(_el$74, () => bytes(progress().total ?? 0), null);
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);
4684
4652
  effect((_p$) => {
4685
4653
  var _v$30 = palette.foreground, _v$31 = TextAttributes2.BOLD;
4686
- _v$30 !== _p$.e && (_p$.e = setProp(_el$74, "fg", _v$30, _p$.e));
4687
- _v$31 !== _p$.t && (_p$.t = setProp(_el$74, "attributes", _v$31, _p$.t));
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));
4688
4656
  return _p$;
4689
4657
  }, {
4690
4658
  e: void 0,
4691
4659
  t: void 0
4692
4660
  });
4693
- return _el$74;
4661
+ return _el$73;
4694
4662
  })(), (() => {
4695
- var _el$77 = createElement("text");
4696
- insert(_el$77, (() => {
4663
+ var _el$76 = createElement("text");
4664
+ insert(_el$76, (() => {
4697
4665
  var _c$9 = memo2(() => !!progress().speed);
4698
4666
  return () => _c$9() ? `${bytes(progress().speed)} / s` : "";
4699
4667
  })());
4700
- effect((_$p) => setProp(_el$77, "fg", palette.muted, _$p));
4701
- return _el$77;
4668
+ effect((_$p) => setProp(_el$76, "fg", palette.muted, _$p));
4669
+ return _el$76;
4702
4670
  })()];
4703
4671
  }
4704
4672
  }), (() => {
4705
- var _el$78 = createElement("text");
4706
- insertNode(_el$78, createTextNode(`Keep the USB connected until safe removal succeeds.`));
4707
- effect((_$p) => setProp(_el$78, "fg", palette.warning, _$p));
4708
- return _el$78;
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;
4709
4677
  })()];
4710
4678
  }
4711
4679
  }), createComponent2(Show, {
@@ -4714,37 +4682,34 @@ function App(props) {
4714
4682
  },
4715
4683
  get children() {
4716
4684
  return [(() => {
4717
- var _el$80 = createElement("text");
4718
- insert(_el$80, () => props.backend.successTitle);
4685
+ var _el$79 = createElement("text");
4686
+ insert(_el$79, () => props.backend.successTitle);
4719
4687
  effect((_p$) => {
4720
4688
  var _v$32 = palette.success, _v$33 = TextAttributes2.BOLD;
4721
- _v$32 !== _p$.e && (_p$.e = setProp(_el$80, "fg", _v$32, _p$.e));
4722
- _v$33 !== _p$.t && (_p$.t = setProp(_el$80, "attributes", _v$33, _p$.t));
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));
4723
4691
  return _p$;
4724
4692
  }, {
4725
4693
  e: void 0,
4726
4694
  t: void 0
4727
4695
  });
4696
+ return _el$79;
4697
+ })(), (() => {
4698
+ var _el$80 = createElement("text");
4699
+ insert(_el$80, () => props.backend.successDetail);
4700
+ effect((_$p) => setProp(_el$80, "fg", palette.foreground, _$p));
4728
4701
  return _el$80;
4729
4702
  })(), (() => {
4730
4703
  var _el$81 = createElement("text");
4731
- insert(_el$81, () => props.backend.successDetail);
4732
- effect((_$p) => setProp(_el$81, "fg", palette.foreground, _$p));
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));
4733
4706
  return _el$81;
4734
4707
  })(), (() => {
4735
- var _el$82 = createElement("text");
4736
- insert(_el$82, (() => {
4737
- var _c$0 = memo2(() => !!props.backend.demo);
4738
- return () => _c$0() ? "The real flow checks the write, flush and safe removal." : catalog()?.candidate ? "GitHub ZIP, compressed image and raw stream verified. Not a device read-back." : "Compressed image and raw stream verified. Not a device read-back.";
4739
- })());
4740
- effect((_$p) => setProp(_el$82, "fg", palette.muted, _$p));
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);
4741
4712
  return _el$82;
4742
- })(), (() => {
4743
- var _el$83 = createElement("box");
4744
- setProp(_el$83, "gap", 1);
4745
- insert(_el$83, () => row("Choose another image", "", 0), null);
4746
- insert(_el$83, () => row("Quit", "", 1), null);
4747
- return _el$83;
4748
4713
  })()];
4749
4714
  }
4750
4715
  }), createComponent2(Show, {
@@ -4753,56 +4718,56 @@ function App(props) {
4753
4718
  },
4754
4719
  get children() {
4755
4720
  return [(() => {
4756
- var _el$84 = createElement("text");
4757
- insertNode(_el$84, createTextNode(`Flash not completed`));
4721
+ var _el$83 = createElement("text");
4722
+ insertNode(_el$83, createTextNode(`Flash not completed`));
4758
4723
  effect((_p$) => {
4759
4724
  var _v$34 = palette.danger, _v$35 = TextAttributes2.BOLD;
4760
- _v$34 !== _p$.e && (_p$.e = setProp(_el$84, "fg", _v$34, _p$.e));
4761
- _v$35 !== _p$.t && (_p$.t = setProp(_el$84, "attributes", _v$35, _p$.t));
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));
4762
4727
  return _p$;
4763
4728
  }, {
4764
4729
  e: void 0,
4765
4730
  t: void 0
4766
4731
  });
4767
- return _el$84;
4732
+ return _el$83;
4768
4733
  })(), (() => {
4769
- var _el$86 = createElement("text");
4770
- insert(_el$86, error);
4771
- effect((_$p) => setProp(_el$86, "fg", palette.foreground, _$p));
4772
- return _el$86;
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;
4773
4738
  })(), (() => {
4774
- var _el$87 = createElement("box");
4775
- setProp(_el$87, "gap", 1);
4776
- insert(_el$87, () => row("Refresh & try again", "", 0), null);
4777
- insert(_el$87, () => row("Quit", "", 1), null);
4778
- return _el$87;
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;
4779
4744
  })()];
4780
4745
  }
4781
4746
  })];
4782
4747
  }
4783
4748
  }));
4784
- setProp(_el$88, "height", 1);
4785
- setProp(_el$88, "flexShrink", 0);
4786
- setProp(_el$88, "wrapMode", "none");
4787
- insert(_el$88, (() => {
4788
- var _c$1 = memo2(() => !!busy());
4789
- return () => _c$1() ? "Esc cancel / Q stop & quit" : dimensions().width < 56 ? "Arrows / Enter / Esc / R / Q quit" : "Arrows / Enter / Esc back / R refresh / Q quit";
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";
4790
4755
  })());
4791
4756
  effect((_p$) => {
4792
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;
4793
- _v$36 !== _p$.e && (_p$.e = setProp(_el$5, "backgroundColor", _v$36, _p$.e));
4794
- _v$37 !== _p$.t && (_p$.t = setProp(_el$6, "width", _v$37, _p$.t));
4795
- _v$38 !== _p$.a && (_p$.a = setProp(_el$6, "height", _v$38, _p$.a));
4796
- _v$39 !== _p$.o && (_p$.o = setProp(_el$6, "borderColor", _v$39, _p$.o));
4797
- _v$40 !== _p$.i && (_p$.i = setProp(_el$6, "backgroundColor", _v$40, _p$.i));
4798
- _v$41 !== _p$.n && (_p$.n = setProp(_el$8, "fg", _v$41, _p$.n));
4799
- _v$42 !== _p$.s && (_p$.s = setProp(_el$8, "attributes", _v$42, _p$.s));
4800
- _v$43 !== _p$.h && (_p$.h = setProp(_el$0, "fg", _v$43, _p$.h));
4801
- _v$44 !== _p$.r && (_p$.r = setProp(_el$1, "backgroundColor", _v$44, _p$.r));
4802
- _v$45 !== _p$.d && (_p$.d = setProp(_el$1, "marginTop", _v$45, _p$.d));
4803
- _v$46 !== _p$.l && (_p$.l = setProp(_el$10, "paddingTop", _v$46, _p$.l));
4804
- _v$47 !== _p$.u && (_p$.u = setProp(_el$10, "gap", _v$47, _p$.u));
4805
- _v$48 !== _p$.c && (_p$.c = setProp(_el$88, "fg", _v$48, _p$.c));
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));
4806
4771
  return _p$;
4807
4772
  }, {
4808
4773
  e: void 0,
@@ -4819,7 +4784,7 @@ function App(props) {
4819
4784
  u: void 0,
4820
4785
  c: void 0
4821
4786
  });
4822
- return _el$5;
4787
+ return _el$4;
4823
4788
  })();
4824
4789
  }
4825
4790
 
@@ -4827,8 +4792,8 @@ function App(props) {
4827
4792
  var args = process.argv.slice(2);
4828
4793
  var demo = args.includes("--demo");
4829
4794
  var fixture = args.find((arg) => arg.startsWith("--demo="))?.slice(7);
4830
- if (args.length > 1 || args.some((arg) => !["--demo", "--demo=empty", "--demo=error", "--demo=setup", "--demo=setup-gh", "--demo=setup-zstd", "--demo=setup-error", "--demo=setup-interrupted", "--demo=no-homebrew", "--list-images", "--clear-cache"].includes(arg))) {
4831
- console.error("Usage: bun start [--demo[=empty|error|setup|setup-gh|setup-zstd|setup-error|setup-interrupted|no-homebrew] | --list-images | --clear-cache]");
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]");
4832
4797
  process.exitCode = 1;
4833
4798
  } else if (args.includes("--clear-cache")) {
4834
4799
  try {