boo-flash 0.1.5 → 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 +71 -114
  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}$/;
@@ -3529,35 +3522,49 @@ async function discoverImages(signal) {
3529
3522
  });
3530
3523
  return { run: build, version: channel.version, revision: channel.revision, timestamp, images };
3531
3524
  }
3532
- async function discoverCandidates(signal) {
3533
- const api = async (path) => JSON.parse(await command(["gh", "api", "--hostname", "github.com", `repos/${repository}/${path}`], signal));
3534
- const result = await api("actions/workflows/candidate.yml/runs?status=success&per_page=10");
3535
- if (!Array.isArray(result.workflow_runs)) throw new Error("Invalid GitHub candidate workflow response.");
3536
- const candidates = [];
3537
- for (const run of result.workflow_runs.slice(0, 10)) {
3538
- 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;
3539
- const batch = await api(`actions/runs/${run.id}/artifacts?per_page=100`);
3540
- if (!Array.isArray(batch.artifacts)) throw new Error("Invalid GitHub artifact response.");
3541
- for (const a of batch.artifacts) {
3542
- const match = /^boo-(intel|amd|nvidia)-candidate-([a-f0-9]{40})$/.exec(a.name);
3543
- 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;
3544
- candidates.push({
3545
- run: run.id,
3546
- revision: match[2],
3547
- timestamp: new Date(run.created_at).toISOString(),
3548
- images: [{
3549
- profile: match[1],
3550
- id: a.id,
3551
- name: a.name,
3552
- bytes: a.size_in_bytes,
3553
- digest: a.digest.slice(7)
3554
- }],
3555
- candidate: { number: run.run_number }
3556
- });
3557
- 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.");
3558
3535
  }
3559
- }
3560
- 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 })));
3561
3568
  }
3562
3569
  var FlashBackend = class {
3563
3570
  constructor(demo2) {
@@ -3583,11 +3590,11 @@ var FlashBackend = class {
3583
3590
  if (this.demo) return "Demo only: no cached images or USB contents were changed.";
3584
3591
  return clearCachedImages(signal);
3585
3592
  }
3586
- dependencies(includeGitHub = false) {
3587
- if (!this.demo) return this.requirePlatform().dependencies(includeGitHub);
3593
+ dependencies() {
3594
+ if (!this.demo) return this.requirePlatform().dependencies();
3588
3595
  const setup = this.demo.startsWith("setup") || this.demo === "no-homebrew";
3589
3596
  return {
3590
- 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"],
3591
3598
  installer: this.demo === "no-homebrew" ? null : "Homebrew",
3592
3599
  guidance: "Demo dependency guidance."
3593
3600
  };
@@ -3663,18 +3670,14 @@ var FlashBackend = class {
3663
3670
  if (process.getuid?.() === 0) throw new Error(`Run Boo Flash on ${platform3.id === "macos" ? "macOS" : "Linux"} as your normal user, not with sudo.`);
3664
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.");
3665
3672
  if (catalog.candidate) {
3666
- 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.");
3667
- const artifact = JSON.parse(await command(["gh", "api", "--hostname", "github.com", `repos/${repository}/actions/artifacts/${image.id}`], signal));
3668
- 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}`) {
3669
- throw new Error("Selected candidate artifact changed or expired. Refresh Candidates. No disk was written.");
3670
- }
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.");
3671
3674
  } else {
3672
3675
  const build = Number(catalog.version?.slice(catalog.version.lastIndexOf("+") + 1));
3673
3676
  const name2 = `boo-${catalog.version}-x86_64-${image.profile}.raw.zst`;
3674
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.");
3675
3678
  }
3676
3679
  const staging = await mkdtemp(join5(tmpdir4(), "boo-flash-"));
3677
- const payload = join5(staging, catalog.candidate ? "image.zip" : "image.raw.zst");
3680
+ const payload = join5(staging, "image.raw.zst");
3678
3681
  let unretained = false;
3679
3682
  let destructive = false;
3680
3683
  try {
@@ -3682,17 +3685,17 @@ var FlashBackend = class {
3682
3685
  let count = 0;
3683
3686
  if (!await reuseArchive(image, payload, signal, (count2) => update({
3684
3687
  stage: "Using cached image",
3685
- 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.`,
3686
3689
  bytes: count2,
3687
3690
  total: image.bytes
3688
3691
  }))) {
3689
3692
  const payloadFile = await open2(payload, "wx", 384);
3690
3693
  const payloadHash = createHash2("sha256");
3691
3694
  const started = performance.now();
3692
- 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.`;
3693
3696
  update({ stage: "Downloading", detail, bytes: 0, total: image.bytes });
3694
3697
  try {
3695
- 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];
3696
3699
  await command(argv, signal, {
3697
3700
  limit: image.bytes,
3698
3701
  consume: async (chunk) => {
@@ -3712,60 +3715,17 @@ var FlashBackend = class {
3712
3715
  await payloadFile.close();
3713
3716
  }
3714
3717
  if (count !== image.bytes || payloadHash.digest("hex") !== image.digest) {
3715
- 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.`);
3716
3719
  }
3717
3720
  unretained = true;
3718
3721
  await publishArchive(image, payload, signal);
3719
3722
  unretained = false;
3720
3723
  }
3721
3724
  signal.throwIfAborted();
3722
- let compressed = payload;
3723
- let rawBytes = image.rawBytes;
3724
- let rawDigest = image.rawDigest;
3725
- if (catalog.candidate) {
3726
- update({ stage: "Verifying", detail: "Checking GitHub ZIP digest, build identity and image checksums." });
3727
- const names = (await command(["unzip", "-Z1", payload], signal)).trim().split("\n");
3728
- for (const name2 of ["build-info.json", "SHA256SUMS", "SHA256SUMS.raw"]) {
3729
- if (names.filter((n) => n === name2).length !== 1) throw new Error(`Archive is missing a unique ${name2}.`);
3730
- }
3731
- const extractText = (name2) => command(["unzip", "-p", payload, name2], signal, { limit: 1024 ** 2 });
3732
- const metadata = JSON.parse(await extractText("build-info.json"));
3733
- const basename2 = `boo-${image.profile}-x86_64.raw.zst`;
3734
- if (metadata.semantic_version !== void 0 && (!semanticVersion.test(metadata.semantic_version) || metadata.build_number !== null || metadata.version !== metadata.semantic_version)) {
3735
- throw new Error("Build metadata has an invalid candidate image version.");
3736
- }
3737
- 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)) {
3738
- throw new Error("Build metadata does not match the selected candidate.");
3739
- }
3740
- 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()) {
3741
- throw new Error("Candidate source metadata does not match the selected artifact.");
3742
- }
3743
- if ((await extractText("SHA256SUMS")).trim() !== `${metadata.compressed_sha256} ${basename2}` || (await extractText("SHA256SUMS.raw")).trim() !== `${metadata.raw_sha256} ${basename2.slice(0, -4)}`) {
3744
- throw new Error("Image checksum manifests disagree with build metadata.");
3745
- }
3746
- compressed = join5(staging, basename2);
3747
- const file = await open2(compressed, "wx", 384);
3748
- const hash = createHash2("sha256");
3749
- count = 0;
3750
- try {
3751
- await command(["unzip", "-p", payload, basename2], signal, {
3752
- limit: metadata.compressed_bytes,
3753
- consume: async (chunk) => {
3754
- hash.update(chunk);
3755
- await file.writeFile(chunk);
3756
- count += chunk.length;
3757
- update({ stage: "Verifying", detail: "Extracting only the selected image; checking compressed SHA-256.", bytes: count, total: metadata.compressed_bytes });
3758
- }
3759
- });
3760
- } finally {
3761
- await file.close();
3762
- }
3763
- if (count !== metadata.compressed_bytes || hash.digest("hex") !== metadata.compressed_sha256) throw new Error("Compressed image size or SHA-256 mismatch.");
3764
- rawBytes = metadata.raw_apparent_bytes;
3765
- rawDigest = metadata.raw_sha256;
3766
- } else {
3767
- update({ stage: "Verifying", detail: `Boo ${catalog.version} release metadata and compressed SHA-256 verified.` });
3768
- }
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.` });
3769
3729
  if (!positive(rawBytes) || !sha256.test(rawDigest ?? "")) throw new Error("Image raw-stream metadata is invalid.");
3770
3730
  if (rawBytes > disk.bytes) throw new Error(`Image needs ${bytes(rawBytes)}; the selected USB is too small.`);
3771
3731
  const revalidate = async (unmounted = false) => {
@@ -3897,7 +3857,7 @@ function App(props) {
3897
3857
  if (!closing) {
3898
3858
  const setup = screen() === "installing";
3899
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.");
3900
- if (setup) setDependencies(props.backend.dependencies(setupCandidates()));
3860
+ if (setup) setDependencies(props.backend.dependencies());
3901
3861
  setScreen(setup ? "setup" : "error");
3902
3862
  setCursor(0);
3903
3863
  }
@@ -3932,7 +3892,7 @@ function App(props) {
3932
3892
  setCursor(0);
3933
3893
  setScreen("candidates");
3934
3894
  operation(async (signal) => {
3935
- const state = props.backend.dependencies(true);
3895
+ const state = props.backend.dependencies();
3936
3896
  if (state.missing.length) {
3937
3897
  setDependencies(state);
3938
3898
  setScreen("setup");
@@ -4741,10 +4701,7 @@ function App(props) {
4741
4701
  return _el$80;
4742
4702
  })(), (() => {
4743
4703
  var _el$81 = createElement("text");
4744
- insert(_el$81, (() => {
4745
- var _c$0 = memo2(() => !!props.backend.demo);
4746
- 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.";
4747
- })());
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.");
4748
4705
  effect((_$p) => setProp(_el$81, "fg", palette.muted, _$p));
4749
4706
  return _el$81;
4750
4707
  })(), (() => {
@@ -4793,8 +4750,8 @@ function App(props) {
4793
4750
  setProp(_el$87, "flexShrink", 0);
4794
4751
  setProp(_el$87, "wrapMode", "none");
4795
4752
  insert(_el$87, (() => {
4796
- var _c$1 = memo2(() => !!busy());
4797
- 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";
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";
4798
4755
  })());
4799
4756
  effect((_p$) => {
4800
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;
@@ -4835,8 +4792,8 @@ function App(props) {
4835
4792
  var args = process.argv.slice(2);
4836
4793
  var demo = args.includes("--demo");
4837
4794
  var fixture = args.find((arg) => arg.startsWith("--demo="))?.slice(7);
4838
- 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))) {
4839
- 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]");
4840
4797
  process.exitCode = 1;
4841
4798
  } else if (args.includes("--clear-cache")) {
4842
4799
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "boo-flash",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Flash qualified Boo images to USB drives on macOS and Linux",
5
5
  "license": "MIT",
6
6
  "type": "module",