create-vidra-app 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,11 +1,7 @@
1
- // src/cli.ts
2
- import chalk7 from "chalk";
3
-
4
1
  // src/commands/build.ts
5
2
  import path5 from "path";
6
3
  import fs4 from "fs-extra";
7
4
  import { execSync as execSync3 } from "child_process";
8
- import chalk5 from "chalk";
9
5
 
10
6
  // src/utils.ts
11
7
  var parseArgs = (argv) => {
@@ -14,7 +10,17 @@ var parseArgs = (argv) => {
14
10
  const arg = argv[i];
15
11
  if (arg.startsWith("--")) {
16
12
  const [key, val] = arg.slice(2).split("=");
17
- args[key] = val ?? argv[++i] ?? true;
13
+ if (val !== void 0) {
14
+ args[key] = val;
15
+ continue;
16
+ }
17
+ const next = argv[i + 1];
18
+ if (next !== void 0 && !next.startsWith("--")) {
19
+ args[key] = next;
20
+ i++;
21
+ } else {
22
+ args[key] = true;
23
+ }
18
24
  } else {
19
25
  args._.push(arg);
20
26
  }
@@ -24,10 +30,69 @@ var parseArgs = (argv) => {
24
30
 
25
31
  // src/exec.ts
26
32
  import { execSync } from "child_process";
33
+
34
+ // src/theme.ts
27
35
  import chalk from "chalk";
28
- var toText = (value) => {
29
- if (value == null) return "";
30
- return Buffer.isBuffer(value) ? value.toString() : value;
36
+ var CLI_VERSION = "0.1.5";
37
+ var STEP_LABEL_WIDTH = 16;
38
+ var lime = chalk.hex("#c8f751");
39
+ var value = chalk.hex("#e8e8ec");
40
+ var dim = chalk.hex("#7a7a86");
41
+ var amber = chalk.hex("#ffcf5c");
42
+ var green = chalk.hex("#86d98f");
43
+ var red = chalk.hex("#ff8585");
44
+ var slate = chalk.hex("#a9b0bd");
45
+ var uiColor = chalk.hex("#6fd3e0");
46
+ var hostColor = chalk.hex("#a48ce8");
47
+ var GLYPH_CHAR = {
48
+ done: "\u2713",
49
+ active: "\u25B8",
50
+ error: "\u2717",
51
+ manual: "?",
52
+ plan: "\u25C6",
53
+ skip: "\u2298"
54
+ };
55
+ var GLYPH_COLOR = {
56
+ done: green,
57
+ active: lime,
58
+ error: red,
59
+ manual: amber,
60
+ plan: slate,
61
+ skip: slate
62
+ };
63
+ var glyph = (name) => GLYPH_COLOR[name](GLYPH_CHAR[name]);
64
+ var TAG_COLOR = {
65
+ ui: uiColor,
66
+ host: hostColor
67
+ };
68
+ var TAG_WIDTH = 6;
69
+ var tag = (name) => TAG_COLOR[name](`[${name}]`.padEnd(TAG_WIDTH));
70
+ var blankTag = () => " ".repeat(TAG_WIDTH);
71
+ var wordmark = () => lime("vidra");
72
+ var header = (sub, context) => {
73
+ const base = ` ${wordmark()} ${value(sub)}`;
74
+ return context ? `${base} ${dim(`\u2014 ${context}`)}` : base;
75
+ };
76
+ var kv = (label, val, width = 9) => ` ${dim(label.padEnd(width))} ${value(val)}`;
77
+ var row = (opts) => {
78
+ const parts = [` ${glyph(opts.glyph)}`];
79
+ if (opts.label !== void 0) {
80
+ const padded = opts.labelWidth ? opts.label.padEnd(opts.labelWidth) : opts.label;
81
+ parts.push(value(padded));
82
+ }
83
+ if (opts.detail) parts.push(opts.detail);
84
+ return parts.join(" ");
85
+ };
86
+ var taggedRow = (glyphName, tagName, text) => ` ${glyph(glyphName)} ${tagName ? tag(tagName) : blankTag()} ${text}`;
87
+ var streamPrefix = (tagName) => ` ${dim("\xB7")} ${tag(tagName)}`;
88
+ var footer = (content) => ` ${content}`;
89
+ var fixLine = (cmd, label = "fix:") => ` ${amber(label)} ${lime(cmd)}`;
90
+ var planBadge = (text = "PLAN ONLY \xB7 BEING BUILT") => amber(`[ ${text} ]`);
91
+
92
+ // src/exec.ts
93
+ var toText = (value2) => {
94
+ if (value2 == null) return "";
95
+ return Buffer.isBuffer(value2) ? value2.toString() : value2;
31
96
  };
32
97
  var formatProcessError = (error) => {
33
98
  const err = error;
@@ -49,7 +114,6 @@ var formatBuildError = (error) => {
49
114
  // src/project.ts
50
115
  import path from "path";
51
116
  import fs from "fs-extra";
52
- import chalk2 from "chalk";
53
117
  var detectPlatform = () => {
54
118
  switch (process.platform) {
55
119
  case "darwin":
@@ -88,9 +152,15 @@ var detectProject = (cwd) => {
88
152
  dir = parent;
89
153
  }
90
154
  console.error(
91
- chalk2.red(
92
- " Could not detect Vidra project. Run this command from your project root.\n Expected: package.json, ui/, src/<Name>.Host/<Name>.Host.csproj"
93
- )
155
+ row({
156
+ glyph: "error",
157
+ detail: dim(
158
+ "Could not detect Vidra project. Run this command from your project root."
159
+ )
160
+ })
161
+ );
162
+ console.error(
163
+ footer(dim("expected: package.json, ui/, src/<Name>.Host/<Name>.Host.csproj"))
94
164
  );
95
165
  process.exit(1);
96
166
  };
@@ -161,7 +231,6 @@ var macosTarget = {
161
231
  // src/signing.ts
162
232
  import path3 from "path";
163
233
  import { execFileSync } from "child_process";
164
- import chalk3 from "chalk";
165
234
  var signMacAppBundleIfPossible = (appBundle, options) => {
166
235
  if (process.platform !== "darwin") return;
167
236
  const identity = resolveMacCodeSigningIdentity();
@@ -176,20 +245,30 @@ var signMacAppBundleIfPossible = (appBundle, options) => {
176
245
  }
177
246
  );
178
247
  options.log(
179
- identity ? ` ${chalk3.dim("Signing:")} ${chalk3.cyan(label)} ${chalk3.dim(`with ${identity}`)}` : ` ${chalk3.dim("Signing:")} ${chalk3.cyan(label)} ${chalk3.dim("ad-hoc (no developer identity)")}`
248
+ row({
249
+ glyph: "done",
250
+ label: "codesign",
251
+ labelWidth: STEP_LABEL_WIDTH,
252
+ detail: identity ? `${value(label)} ${dim(`with ${identity}`)}` : `${value(label)} ${dim("ad-hoc (-)")}`
253
+ })
180
254
  );
181
255
  } catch (error) {
182
256
  options.warn(
183
- chalk3.yellow(
184
- " Could not code-sign the macOS app bundle; it may fail to launch."
185
- )
257
+ row({
258
+ glyph: "manual",
259
+ label: "codesign",
260
+ labelWidth: STEP_LABEL_WIDTH,
261
+ detail: dim("could not sign the app bundle; it may fail to launch")
262
+ })
186
263
  );
187
264
  options.warn(
188
- chalk3.yellow(
189
- " Install Xcode or the Command Line Tools (provides `codesign`), or set VIDRA_MACOS_CODESIGN_KEY."
265
+ footer(
266
+ dim(
267
+ "install Xcode or the Command Line Tools (provides `codesign`), or set VIDRA_MACOS_CODESIGN_KEY."
268
+ )
190
269
  )
191
270
  );
192
- options.warn(chalk3.dim(formatExecError(error)));
271
+ options.warn(dim(formatExecError(error)));
193
272
  }
194
273
  };
195
274
  var resolveMacCodeSigningIdentity = () => {
@@ -206,7 +285,7 @@ var resolveMacCodeSigningIdentity = () => {
206
285
  encoding: "utf8"
207
286
  }
208
287
  );
209
- const identities = output.split(/\r?\n/).map((line) => line.match(/"([^"]+)"/)?.[1] ?? null).filter((value) => value !== null);
288
+ const identities = output.split(/\r?\n/).map((line) => line.match(/"([^"]+)"/)?.[1] ?? null).filter((value2) => value2 !== null);
210
289
  return identities.find((identity) => identity.startsWith("Apple Development:")) ?? identities.find((identity) => identity.startsWith("Developer ID Application:")) ?? null;
211
290
  } catch {
212
291
  return null;
@@ -225,45 +304,74 @@ var formatExecError = (error) => {
225
304
 
226
305
  // src/targets/windows.ts
227
306
  import path4 from "path";
307
+ import os2 from "os";
228
308
  import fs3 from "fs-extra";
309
+ import { execFileSync as execFileSync2 } from "child_process";
229
310
  var windowsTarget = {
230
311
  name: "windows",
231
312
  framework: "net10.0-windows10.0.19041.0",
232
- extraPublishArgs: "-p:RuntimeIdentifierOverride=win-x64 -p:WindowsPackageType=MSIX",
313
+ // `RuntimeIdentifierOverride` (rather than `-r`/`RuntimeIdentifier`) is the
314
+ // MAUI-recommended way to set the Windows RID — it sidesteps WindowsAppSDK
315
+ // issue #3337, which otherwise pulls in the wrong packaging assets.
316
+ extraPublishArgs: "-p:WindowsPackageType=None -p:SelfContained=true -p:WindowsAppSDKSelfContained=true -p:RuntimeIdentifierOverride=win-x64",
233
317
  findBundle(publishDir, _projectName) {
234
- const appPackagesDir = path4.join(publishDir, "win-x64", "AppPackages");
235
- if (!fs3.existsSync(appPackagesDir)) return null;
236
- for (const entry of fs3.readdirSync(appPackagesDir, {
237
- withFileTypes: true
238
- })) {
239
- if (!entry.isDirectory()) continue;
240
- const subDir = path4.join(appPackagesDir, entry.name);
241
- for (const file of fs3.readdirSync(subDir)) {
242
- if (file.endsWith(".msix")) {
243
- return path4.join(subDir, file);
244
- }
245
- }
246
- }
247
- return null;
318
+ const preferred = path4.join(publishDir, "win-x64", "publish");
319
+ if (dirContainsExe(preferred)) return preferred;
320
+ return findDirWithExe(publishDir);
248
321
  },
249
- async package(msixPath, outputDir, meta) {
250
- const outName = `${meta.projectName}-${meta.displayVersion}-windows.msix`;
322
+ async package(publishOutputDir, outputDir, meta) {
323
+ const outName = `${meta.projectName}-${meta.displayVersion}-windows.zip`;
251
324
  const outPath = path4.join(outputDir, outName);
252
- fs3.copySync(msixPath, outPath, { overwrite: true });
325
+ if (fs3.existsSync(outPath)) fs3.removeSync(outPath);
326
+ const staging = fs3.mkdtempSync(path4.join(os2.tmpdir(), "vidra-zip-"));
327
+ const stagedApp = path4.join(staging, meta.projectName);
328
+ try {
329
+ fs3.copySync(publishOutputDir, stagedApp);
330
+ execFileSync2(
331
+ "powershell",
332
+ [
333
+ "-NoProfile",
334
+ "-NonInteractive",
335
+ "-Command",
336
+ `Compress-Archive -Path "${stagedApp}" -DestinationPath "${outPath}" -Force`
337
+ ],
338
+ { stdio: "pipe" }
339
+ );
340
+ } finally {
341
+ fs3.removeSync(staging);
342
+ }
253
343
  return outPath;
254
344
  }
255
345
  };
346
+ var dirContainsExe = (dir) => fs3.existsSync(dir) && fs3.readdirSync(dir, { withFileTypes: true }).some((e) => e.isFile() && e.name.toLowerCase().endsWith(".exe"));
347
+ var findDirWithExe = (root) => {
348
+ if (!fs3.existsSync(root)) return null;
349
+ let fallback = null;
350
+ const walk = (dir) => {
351
+ if (dirContainsExe(dir)) {
352
+ if (path4.basename(dir) === "publish") return dir;
353
+ fallback ??= dir;
354
+ }
355
+ for (const e of fs3.readdirSync(dir, { withFileTypes: true })) {
356
+ if (e.isDirectory()) {
357
+ const found = walk(path4.join(dir, e.name));
358
+ if (found) return found;
359
+ }
360
+ }
361
+ return null;
362
+ };
363
+ return walk(root) ?? fallback;
364
+ };
256
365
 
257
366
  // src/doctor.ts
258
- import { execFileSync as execFileSync2 } from "child_process";
367
+ import { execFileSync as execFileSync3 } from "child_process";
259
368
  import prompts from "prompts";
260
- import chalk4 from "chalk";
261
369
  var DOTNET = process.platform === "win32" ? "dotnet.exe" : "dotnet";
262
370
  var MAUI_DOCS = "https://learn.microsoft.com/dotnet/maui/get-started/installation";
263
371
  var bufToStr = (v) => v == null ? "" : Buffer.isBuffer(v) ? v.toString() : v;
264
372
  var run = (cmd, args) => {
265
373
  try {
266
- const stdout = execFileSync2(cmd, args, {
374
+ const stdout = execFileSync3(cmd, args, {
267
375
  encoding: "utf-8",
268
376
  stdio: ["ignore", "pipe", "pipe"]
269
377
  });
@@ -384,19 +492,32 @@ var collectRequirements = (opts = {}) => {
384
492
  }
385
493
  return reqs;
386
494
  };
495
+ var STATUS_GLYPH = {
496
+ ok: "done",
497
+ missing: "error",
498
+ unknown: "manual"
499
+ };
387
500
  var printRequirements = (reqs) => {
501
+ const labelWidth = Math.max(0, ...reqs.map((r) => r.name.length)) + 2;
388
502
  for (const r of reqs) {
389
- const icon = r.status === "ok" ? chalk4.green("\u2713") : r.status === "missing" ? chalk4.red("\u2717") : chalk4.yellow("?");
390
- const detail = r.detail ? ` ${chalk4.dim(`(${r.detail})`)}` : "";
391
- console.log(` ${icon} ${r.name}${detail}`);
503
+ console.log(
504
+ row({
505
+ glyph: STATUS_GLYPH[r.status],
506
+ label: r.name,
507
+ labelWidth,
508
+ detail: r.detail ? dim(r.detail) : void 0
509
+ })
510
+ );
392
511
  if (r.status === "missing" && r.fix) {
393
- console.log(` ${chalk4.dim("fix:")} ${chalk4.cyan(r.fix)}`);
512
+ console.log(fixLine(r.fix));
394
513
  }
395
514
  }
396
515
  };
397
516
  var runDoctor = async () => {
398
517
  console.log();
399
- console.log(` ${chalk4.bold.cyan("vidra doctor")}`);
518
+ console.log(` ${lime("vidra")} ${value("doctor")}`);
519
+ console.log();
520
+ console.log(footer(dim("checking your environment\u2026")));
400
521
  console.log();
401
522
  const reqs = collectRequirements();
402
523
  printRequirements(reqs);
@@ -404,17 +525,22 @@ var runDoctor = async () => {
404
525
  const missing = reqs.filter((r) => r.status === "missing");
405
526
  if (missing.length === 0) {
406
527
  console.log(
407
- ` ${chalk4.green("All checks passed.")} You're ready to run ${chalk4.cyan(
408
- "vidra dev"
409
- )}.`
528
+ footer(
529
+ `${dim("all checks passed \u2014 you're ready to run")} ${lime(
530
+ "vidra dev"
531
+ )}${dim(".")}`
532
+ )
410
533
  );
411
534
  console.log();
412
535
  return 0;
413
536
  }
537
+ const n = missing.length;
414
538
  console.log(
415
- ` ${chalk4.yellow(
416
- `${missing.length} issue(s) found.`
417
- )} Apply the fixes above, then re-run ${chalk4.cyan("vidra doctor")}.`
539
+ footer(
540
+ `${dim(
541
+ `${n} issue${n === 1 ? "" : "s"} found. apply the ${n === 1 ? "fix" : "fixes"} above, then re-run`
542
+ )} ${lime("vidra doctor")}${dim(".")}`
543
+ )
418
544
  );
419
545
  console.log();
420
546
  return 1;
@@ -422,25 +548,32 @@ var runDoctor = async () => {
422
548
  var installWorkload = (csprojPath) => {
423
549
  const args = csprojPath ? ["workload", "restore", csprojPath] : ["workload", "install", "maui"];
424
550
  console.log();
425
- console.log(` ${chalk4.dim(`Running: ${DOTNET} ${args.join(" ")}`)}`);
426
551
  console.log(
427
- ` ${chalk4.dim(
428
- "This can download several hundred MB and take a few minutes."
429
- )}`
552
+ row({
553
+ glyph: "active",
554
+ detail: `${dim("running")} ${value(`${DOTNET} ${args.join(" ")}`)}`
555
+ })
556
+ );
557
+ console.log(
558
+ footer(
559
+ dim("this can download several hundred MB and take a few minutes.")
560
+ )
430
561
  );
431
562
  console.log();
432
563
  try {
433
- execFileSync2(DOTNET, args, { stdio: "inherit" });
564
+ execFileSync3(DOTNET, args, { stdio: "inherit" });
434
565
  return true;
435
566
  } catch {
436
567
  console.error();
437
- console.error(` ${chalk4.red("Workload install failed.")}`);
568
+ console.error(row({ glyph: "error", label: "workload install failed" }));
438
569
  console.error(
439
- ` ${chalk4.dim(
440
- "If this is a permissions error, your SDK is in a system location and needs elevation:"
441
- )}`
570
+ footer(
571
+ dim(
572
+ "if this is a permissions error, your SDK is in a system location and needs elevation:"
573
+ )
574
+ )
442
575
  );
443
- console.error(` ${chalk4.cyan("sudo dotnet workload install maui")}`);
576
+ console.error(fixLine("sudo dotnet workload install maui"));
444
577
  console.error();
445
578
  return false;
446
579
  }
@@ -449,9 +582,15 @@ var ensureMauiWorkload = async (opts = {}) => {
449
582
  const dotnet = checkDotnetSdk();
450
583
  if (dotnet.status === "missing") {
451
584
  console.log();
452
- console.log(` ${chalk4.yellow("!")} ${dotnet.name} \u2014 ${dotnet.detail}`);
585
+ console.log(
586
+ row({
587
+ glyph: "error",
588
+ label: dotnet.name,
589
+ detail: dotnet.detail ? dim(dotnet.detail) : void 0
590
+ })
591
+ );
453
592
  if (dotnet.fix) {
454
- console.log(` ${chalk4.dim("fix:")} ${chalk4.cyan(dotnet.fix)}`);
593
+ console.log(fixLine(dotnet.fix));
455
594
  }
456
595
  return false;
457
596
  }
@@ -459,7 +598,11 @@ var ensureMauiWorkload = async (opts = {}) => {
459
598
  if (isMauiWorkloadInstalled()) return true;
460
599
  console.log();
461
600
  console.log(
462
- ` ${chalk4.yellow("!")} The .NET MAUI workload is required but not installed.`
601
+ row({
602
+ glyph: "error",
603
+ label: ".NET MAUI workload",
604
+ detail: dim("required but not installed")
605
+ })
463
606
  );
464
607
  const interactive = opts.interactive ?? isInteractive();
465
608
  if (interactive) {
@@ -477,80 +620,91 @@ var ensureMauiWorkload = async (opts = {}) => {
477
620
  }
478
621
  if (install) {
479
622
  if (installWorkload(opts.csprojPath) && isMauiWorkloadInstalled()) {
480
- console.log(` ${chalk4.green("\u2713")} MAUI workload installed.`);
623
+ console.log(
624
+ row({
625
+ glyph: "done",
626
+ label: ".NET MAUI workload",
627
+ detail: dim("installed")
628
+ })
629
+ );
481
630
  return true;
482
631
  }
483
632
  return false;
484
633
  }
485
634
  }
486
- console.log(
487
- ` ${chalk4.dim("run:")} ${chalk4.cyan("dotnet workload install maui")}`
488
- );
489
- console.log(` ${chalk4.dim("docs:")} ${chalk4.cyan(MAUI_DOCS)}`);
635
+ console.log(fixLine("dotnet workload install maui", "run:"));
636
+ console.log(fixLine(MAUI_DOCS, "docs:"));
490
637
  return false;
491
638
  };
492
639
  var printWorkloadHint = () => {
493
640
  console.error();
494
641
  console.error(
495
- ` ${chalk4.yellow("This looks like a missing .NET MAUI workload.")}`
496
- );
497
- console.error(
498
- ` ${chalk4.dim("fix: ")} ${chalk4.cyan("dotnet workload install maui")}`
499
- );
500
- console.error(
501
- ` ${chalk4.dim("check:")} ${chalk4.cyan("vidra doctor")}`
642
+ row({ glyph: "manual", label: "this looks like a missing .NET MAUI workload." })
502
643
  );
644
+ console.error(fixLine("dotnet workload install maui"));
645
+ console.error(fixLine("vidra doctor", "check:"));
503
646
  console.error();
504
647
  };
505
648
  var printXcodeHint = () => {
506
649
  console.error();
507
650
  console.error(
508
- ` ${chalk4.yellow(
509
- "Mac Catalyst builds need the full Xcode app, not just the Command Line Tools."
510
- )}`
651
+ row({
652
+ glyph: "manual",
653
+ label: "Mac Catalyst needs the full Xcode app, not just the Command Line Tools."
654
+ })
511
655
  );
512
- console.error(` ${chalk4.dim("1.")} Install Xcode from the App Store`);
656
+ console.error(` ${dim("1.")} ${value("install Xcode from the App Store")}`);
513
657
  console.error(
514
- ` ${chalk4.dim("2.")} ${chalk4.cyan(
658
+ ` ${dim("2.")} ${lime(
515
659
  "sudo xcode-select -s /Applications/Xcode.app/Contents/Developer"
516
660
  )}`
517
661
  );
518
- console.error(
519
- ` ${chalk4.dim("3.")} ${chalk4.cyan("sudo xcodebuild -runFirstLaunch")}`
520
- );
521
- console.error(` ${chalk4.dim("check:")} ${chalk4.cyan("vidra doctor")}`);
662
+ console.error(` ${dim("3.")} ${lime("sudo xcodebuild -runFirstLaunch")}`);
663
+ console.error(fixLine("vidra doctor", "check:"));
522
664
  console.error();
523
665
  };
524
666
 
525
667
  // src/commands/build.ts
526
- var VERSION = "0.1.0";
527
668
  var TARGETS = {
528
669
  macos: macosTarget,
529
670
  windows: windowsTarget
530
671
  };
672
+ var packageLabel = (target) => target.name === "macos" ? "package DMG" : "package ZIP";
673
+ var artifactName = (project, target) => `${project.projectName}-${project.displayVersion}-${target.name}.${target.name === "macos" ? "dmg" : "zip"}`;
531
674
  var buildCommand = async (argv) => {
532
675
  const args = parseArgs(["_", "_", ...argv]);
533
676
  const verbose = !!args["verbose"];
677
+ const plan = !!args["plan"] || !!args["dry-run"];
534
678
  const targetName = args["target"] || detectPlatform();
535
- console.log();
536
- console.log(
537
- ` ${chalk5.bold.cyan("vidra build")} ${chalk5.dim(`v${VERSION}`)}`
538
- );
539
- console.log();
540
679
  const target = TARGETS[targetName];
541
680
  if (!target) {
542
681
  const supported = Object.keys(TARGETS).join(", ");
682
+ console.error();
543
683
  console.error(
544
- chalk5.red(
545
- ` Unsupported target: ${targetName}. Supported: ${supported}`
546
- )
684
+ row({
685
+ glyph: "error",
686
+ detail: dim(`unsupported target: ${targetName} \u2014 supported: ${supported}`)
687
+ })
547
688
  );
548
689
  process.exit(1);
549
690
  }
550
691
  const project = detectProject(process.cwd());
551
- console.log(` ${chalk5.dim("Project:")} ${chalk5.cyan(project.projectName)}`);
552
- console.log(` ${chalk5.dim("Target:")} ${chalk5.cyan(target.name)} (${target.framework})`);
553
692
  console.log();
693
+ console.log(
694
+ header("build", `${target.name} \xB7 Release${plan ? " \xB7 plan" : ""}`)
695
+ );
696
+ console.log(kv("project", project.projectName));
697
+ console.log(kv("target", target.framework));
698
+ console.log();
699
+ if (plan) {
700
+ printBuildPlan(project, target);
701
+ console.log();
702
+ console.log(
703
+ footer(`${dim("nothing has run. re-run without")} ${lime("--plan")} ${dim("to apply.")}`)
704
+ );
705
+ console.log();
706
+ return;
707
+ }
554
708
  if (!await ensureMauiWorkload({ csprojPath: project.csprojPath })) {
555
709
  process.exit(1);
556
710
  }
@@ -560,13 +714,13 @@ var buildCommand = async (argv) => {
560
714
  const bundlePath = target.findBundle(publishDir, project.projectName);
561
715
  if (!bundlePath) {
562
716
  console.error(
563
- chalk5.red(` Could not find build artifact in ${publishDir}`)
717
+ row({
718
+ glyph: "error",
719
+ detail: dim(`could not find build artifact in ${publishDir}`)
720
+ })
564
721
  );
565
722
  process.exit(1);
566
723
  }
567
- console.log(
568
- ` ${chalk5.dim("Bundle:")} ${chalk5.cyan(path5.basename(bundlePath))}`
569
- );
570
724
  if (target.name === "macos") {
571
725
  signMacAppBundleIfPossible(bundlePath, {
572
726
  verbose,
@@ -574,36 +728,77 @@ var buildCommand = async (argv) => {
574
728
  warn: console.warn
575
729
  });
576
730
  }
577
- const outputDir = path5.join(project.root, "dist");
578
- fs4.ensureDirSync(outputDir);
731
+ const outputPath = await stepPackage(project, target, bundlePath);
579
732
  console.log();
580
- console.log(` ${chalk5.dim(`Packaging for ${target.name}...`)}`);
581
- const startPkg = Date.now();
582
- let outputPath;
583
- try {
584
- outputPath = await target.package(bundlePath, outputDir, {
585
- projectName: project.projectName,
586
- displayVersion: project.displayVersion
587
- });
588
- } catch (e) {
589
- console.error(chalk5.red(` Packaging failed.`));
590
- console.error(chalk5.dim(formatProcessError(e)));
591
- process.exit(1);
592
- }
593
- const pkgTime = ((Date.now() - startPkg) / 1e3).toFixed(1);
594
- const sizeBytes = fs4.statSync(outputPath).size;
595
- const sizeMB = (sizeBytes / (1024 * 1024)).toFixed(1);
596
733
  console.log(
597
- ` ${chalk5.green(">")} ${path5.basename(outputPath)} ${chalk5.dim(`(${sizeMB} MB, ${pkgTime}s)`)}`
734
+ footer(
735
+ `${dim("done \u2014")} ${value(path5.relative(project.root, outputPath))}`
736
+ )
598
737
  );
599
738
  console.log();
739
+ };
740
+ var printBuildPlan = (project, target) => {
600
741
  console.log(
601
- ` ${chalk5.green("Done!")} Output: ${chalk5.cyan(path5.relative(project.root, outputPath))}`
742
+ row({
743
+ glyph: "done",
744
+ label: "build UI",
745
+ labelWidth: STEP_LABEL_WIDTH,
746
+ detail: `${dim("vite \u2192")} ${value("ui/dist")}`
747
+ })
602
748
  );
603
- console.log();
749
+ console.log(
750
+ row({
751
+ glyph: "done",
752
+ label: "copy assets",
753
+ labelWidth: STEP_LABEL_WIDTH,
754
+ detail: `${dim("\u2192")} ${value("Resources/Raw/wwwroot")}`
755
+ })
756
+ );
757
+ console.log(
758
+ row({
759
+ glyph: "done",
760
+ label: "publish .NET",
761
+ labelWidth: STEP_LABEL_WIDTH,
762
+ detail: `${dim("Release \xB7")} ${value(target.framework)}`
763
+ })
764
+ );
765
+ if (target.name === "macos") {
766
+ console.log(
767
+ row({
768
+ glyph: "done",
769
+ label: "codesign .app",
770
+ labelWidth: STEP_LABEL_WIDTH,
771
+ detail: dim("Apple Development, or ad-hoc (-)")
772
+ })
773
+ );
774
+ console.log(
775
+ row({
776
+ glyph: "plan",
777
+ label: "notarize",
778
+ labelWidth: STEP_LABEL_WIDTH,
779
+ detail: planBadge()
780
+ })
781
+ );
782
+ console.log(
783
+ row({
784
+ glyph: "active",
785
+ label: "package DMG",
786
+ labelWidth: STEP_LABEL_WIDTH,
787
+ detail: `${dim("hdiutil UDZO \u2192")} ${value(artifactName(project, target))}`
788
+ })
789
+ );
790
+ } else {
791
+ console.log(
792
+ row({
793
+ glyph: "active",
794
+ label: "package ZIP",
795
+ labelWidth: STEP_LABEL_WIDTH,
796
+ detail: `${dim("self-contained \u2192")} ${value(artifactName(project, target))}`
797
+ })
798
+ );
799
+ }
604
800
  };
605
801
  var stepBuildUi = (project, verbose) => {
606
- console.log(` ${chalk5.dim("Building UI...")}`);
607
802
  const start = Date.now();
608
803
  try {
609
804
  execSync3("npm run build", {
@@ -611,19 +806,38 @@ var stepBuildUi = (project, verbose) => {
611
806
  stdio: verbose ? "inherit" : "pipe"
612
807
  });
613
808
  } catch (e) {
614
- console.error(chalk5.red(" Vite build failed."));
615
- console.error(chalk5.dim(formatBuildError(e)));
809
+ console.error(
810
+ row({
811
+ glyph: "error",
812
+ label: "build UI",
813
+ labelWidth: STEP_LABEL_WIDTH,
814
+ detail: dim("vite build failed")
815
+ })
816
+ );
817
+ console.error(dim(formatBuildError(e)));
616
818
  process.exit(1);
617
819
  }
618
820
  const elapsed = ((Date.now() - start) / 1e3).toFixed(1);
619
- console.log(` ${chalk5.green(">")} Vite build complete ${chalk5.dim(`(${elapsed}s)`)}`);
620
- console.log();
821
+ console.log(
822
+ row({
823
+ glyph: "done",
824
+ label: "build UI",
825
+ labelWidth: STEP_LABEL_WIDTH,
826
+ detail: `${dim("vite \u2192")} ${value("ui/dist")} ${dim(`(${elapsed}s)`)}`
827
+ })
828
+ );
621
829
  };
622
830
  var stepCopyAssets = (project) => {
623
- console.log(` ${chalk5.dim("Copying assets to host project...")}`);
624
831
  const viteDist = path5.join(project.uiDir, "dist");
625
832
  if (!fs4.existsSync(viteDist)) {
626
- console.error(chalk5.red(` ui/dist not found. Vite build may have failed.`));
833
+ console.error(
834
+ row({
835
+ glyph: "error",
836
+ label: "copy assets",
837
+ labelWidth: STEP_LABEL_WIDTH,
838
+ detail: dim("ui/dist not found \u2014 vite build may have failed")
839
+ })
840
+ );
627
841
  process.exit(1);
628
842
  }
629
843
  const wwwroot = path5.join(project.hostDir, "Resources", "Raw", "wwwroot");
@@ -631,9 +845,13 @@ var stepCopyAssets = (project) => {
631
845
  fs4.copySync(viteDist, wwwroot);
632
846
  const fileCount = countFiles(wwwroot);
633
847
  console.log(
634
- ` ${chalk5.green(">")} ${fileCount} files -> ${chalk5.dim("Resources/Raw/wwwroot/")}`
848
+ row({
849
+ glyph: "done",
850
+ label: "copy assets",
851
+ labelWidth: STEP_LABEL_WIDTH,
852
+ detail: `${dim("\u2192")} ${value("Resources/Raw/wwwroot")} ${dim(`(${fileCount} files)`)}`
853
+ })
635
854
  );
636
- console.log();
637
855
  };
638
856
  var countFiles = (dir) => {
639
857
  let count = 0;
@@ -647,9 +865,6 @@ var countFiles = (dir) => {
647
865
  return count;
648
866
  };
649
867
  var stepDotnetPublish = (project, target, verbose) => {
650
- console.log(
651
- ` ${chalk5.dim(`Publishing .NET host (${target.framework})...`)}`
652
- );
653
868
  const start = Date.now();
654
869
  const extraArgs = target.extraPublishArgs ?? "-p:CreatePackage=false";
655
870
  try {
@@ -662,37 +877,73 @@ var stepDotnetPublish = (project, target, verbose) => {
662
877
  );
663
878
  } catch (e) {
664
879
  const output = formatBuildError(e);
665
- console.error(chalk5.red(" dotnet publish failed."));
666
- console.error(chalk5.dim(output));
880
+ console.error(
881
+ row({
882
+ glyph: "error",
883
+ label: "publish .NET",
884
+ labelWidth: STEP_LABEL_WIDTH,
885
+ detail: dim("dotnet publish failed")
886
+ })
887
+ );
888
+ console.error(dim(output));
667
889
  if (looksLikeMissingWorkload(output)) printWorkloadHint();
668
890
  else if (looksLikeMissingXcode(output)) printXcodeHint();
669
891
  if (!verbose) {
670
- console.error(
671
- chalk5.dim(" Re-run with --verbose for the full build log.")
672
- );
892
+ console.error(footer(dim("re-run with --verbose for the full build log.")));
673
893
  }
674
894
  process.exit(1);
675
895
  }
676
896
  const elapsed = ((Date.now() - start) / 1e3).toFixed(1);
677
897
  console.log(
678
- ` ${chalk5.green(">")} dotnet publish complete ${chalk5.dim(`(${elapsed}s)`)}`
898
+ row({
899
+ glyph: "done",
900
+ label: "publish .NET",
901
+ labelWidth: STEP_LABEL_WIDTH,
902
+ detail: `${dim("Release \xB7")} ${value(target.framework)} ${dim(`(${elapsed}s)`)}`
903
+ })
679
904
  );
680
- const publishDir = path5.join(
681
- project.hostDir,
682
- "bin",
683
- "Release",
684
- target.framework
905
+ return path5.join(project.hostDir, "bin", "Release", target.framework);
906
+ };
907
+ var stepPackage = async (project, target, bundlePath) => {
908
+ const outputDir = path5.join(project.root, "dist");
909
+ fs4.ensureDirSync(outputDir);
910
+ const start = Date.now();
911
+ let outputPath;
912
+ try {
913
+ outputPath = await target.package(bundlePath, outputDir, {
914
+ projectName: project.projectName,
915
+ displayVersion: project.displayVersion
916
+ });
917
+ } catch (e) {
918
+ console.error(
919
+ row({
920
+ glyph: "error",
921
+ label: packageLabel(target),
922
+ labelWidth: STEP_LABEL_WIDTH,
923
+ detail: dim("packaging failed")
924
+ })
925
+ );
926
+ console.error(dim(formatProcessError(e)));
927
+ process.exit(1);
928
+ }
929
+ const pkgTime = ((Date.now() - start) / 1e3).toFixed(1);
930
+ const sizeMB = (fs4.statSync(outputPath).size / (1024 * 1024)).toFixed(1);
931
+ console.log(
932
+ row({
933
+ glyph: "done",
934
+ label: packageLabel(target),
935
+ labelWidth: STEP_LABEL_WIDTH,
936
+ detail: `${value(path5.basename(outputPath))} ${dim(`(${sizeMB} MB, ${pkgTime}s)`)}`
937
+ })
685
938
  );
686
- return publishDir;
939
+ return outputPath;
687
940
  };
688
941
 
689
942
  // src/commands/dev.ts
690
943
  import path6 from "path";
691
944
  import fs5 from "fs-extra";
692
- import { execFileSync as execFileSync3, spawn } from "child_process";
945
+ import { execFileSync as execFileSync4, spawn } from "child_process";
693
946
  import { request } from "http";
694
- import chalk6 from "chalk";
695
- var VERSION2 = "0.1.0";
696
947
  var POLL_INTERVAL_MS = 500;
697
948
  var POLL_TIMEOUT_MS = 3e4;
698
949
  var NPM_COMMAND = process.platform === "win32" ? "npm.cmd" : "npm";
@@ -718,9 +969,10 @@ var startSession = async (argv, opts) => {
718
969
  if (!target) {
719
970
  const supported = Object.keys(TARGETS2).join(", ");
720
971
  console.error(
721
- chalk6.red(
722
- ` Unsupported target: ${targetName}. Supported: ${supported}`
723
- )
972
+ row({
973
+ glyph: "error",
974
+ detail: dim(`unsupported target: ${targetName} \u2014 supported: ${supported}`)
975
+ })
724
976
  );
725
977
  process.exit(1);
726
978
  }
@@ -751,14 +1003,9 @@ var DevSession = class {
751
1003
  async run() {
752
1004
  this.installSignalHandlers();
753
1005
  console.log();
754
- console.log(
755
- ` ${chalk6.bold.cyan(this.vite ? "vidra dev" : "vidra run")} ${chalk6.dim(`v${VERSION2}`)}`
756
- );
757
- console.log();
758
- console.log(` ${chalk6.dim("Project:")} ${chalk6.cyan(this.project.projectName)}`);
759
- console.log(
760
- ` ${chalk6.dim("Target:")} ${chalk6.cyan(this.target.name)} (${this.target.framework})`
761
- );
1006
+ console.log(header(this.vite ? "dev" : "run", this.target.name));
1007
+ console.log(kv("project", this.project.projectName));
1008
+ console.log(kv("target", this.target.framework));
762
1009
  console.log();
763
1010
  let vite;
764
1011
  if (this.vite) {
@@ -766,23 +1013,50 @@ var DevSession = class {
766
1013
  try {
767
1014
  await waitForServer(this.viteUrl, POLL_TIMEOUT_MS);
768
1015
  } catch (error) {
769
- console.error(chalk6.red(` ${error.message}`));
1016
+ console.error(row({ glyph: "error", detail: dim(error.message) }));
770
1017
  this.shutdown(1);
771
1018
  }
772
- console.log(` ${chalk6.dim("Vite:")} ${chalk6.cyan(this.viteUrl)}`);
773
- console.log();
1019
+ console.log(
1020
+ taggedRow("active", "ui", `${dim("vite ready \u2014")} ${value(this.viteUrl)}`)
1021
+ );
774
1022
  } else {
775
1023
  console.log(
776
- ` ${chalk6.dim("UI:")} ${chalk6.cyan(this.viteUrl)} ${chalk6.dim("(start it separately, e.g. `npm run dev:ui`)")}`
1024
+ taggedRow(
1025
+ "skip",
1026
+ "ui",
1027
+ `${dim("vite not started \u2014")} ${value("npm run dev:ui")}`
1028
+ )
777
1029
  );
778
- console.log();
779
1030
  }
780
1031
  const host = this.target.name === "macos" ? this.launchMacosHost() : this.launchWindowsHost();
1032
+ if (this.vite) {
1033
+ console.log(
1034
+ taggedRow(
1035
+ "active",
1036
+ null,
1037
+ `${lime("hot reload active")} ${dim("\u2014 edit ui/src and save")}`
1038
+ )
1039
+ );
1040
+ console.log();
1041
+ console.log(
1042
+ footer(
1043
+ `${dim("watching")} ${value("ui/")} ${dim(
1044
+ "\xB7 hot reload on save \xB7 ctrl-c to stop"
1045
+ )}`
1046
+ )
1047
+ );
1048
+ } else {
1049
+ console.log();
1050
+ console.log(
1051
+ footer(dim("host only \xB7 serve the UI separately \xB7 ctrl-c to stop"))
1052
+ );
1053
+ }
1054
+ console.log();
781
1055
  await waitForExit(...vite ? [vite, host] : [host]);
782
1056
  }
783
1057
  installSignalHandlers() {
784
1058
  process.on("SIGINT", () => {
785
- console.log("\n\x1B[90m[vidra]\x1B[0m Shutting down...");
1059
+ console.log("\n" + footer(dim("shutting down\u2026")));
786
1060
  this.shutdown(0);
787
1061
  });
788
1062
  process.on("SIGTERM", () => {
@@ -790,19 +1064,24 @@ var DevSession = class {
790
1064
  });
791
1065
  }
792
1066
  startVite() {
793
- console.log(` ${chalk6.dim("Starting Vite dev server...")}`);
1067
+ console.log(taggedRow("active", "ui", dim("starting dev server\u2026")));
794
1068
  const vite = spawn(NPM_COMMAND, ["run", "dev"], {
795
1069
  cwd: this.project.uiDir,
796
- stdio: ["ignore", "pipe", "pipe"]
1070
+ stdio: ["ignore", "pipe", "pipe"],
1071
+ shell: process.platform === "win32"
797
1072
  });
798
1073
  return this.registerChild(vite, "ui", "Vite dev server");
799
1074
  }
800
1075
  launchMacosHost() {
801
1076
  console.log(
802
- ` ${chalk6.dim(`Building MAUI host (${this.target.framework})...`)}`
1077
+ taggedRow(
1078
+ "active",
1079
+ "host",
1080
+ `${dim("building")} ${value(this.target.framework)} ${dim("\u2026")}`
1081
+ )
803
1082
  );
804
1083
  try {
805
- execFileSync3(
1084
+ execFileSync4(
806
1085
  DOTNET_COMMAND,
807
1086
  [
808
1087
  "build",
@@ -819,14 +1098,12 @@ var DevSession = class {
819
1098
  );
820
1099
  } catch (error) {
821
1100
  const output = formatBuildError(error);
822
- console.error(chalk6.red(" MAUI build failed."));
823
- console.error(chalk6.dim(output));
1101
+ console.error(taggedRow("error", "host", dim("MAUI build failed")));
1102
+ console.error(dim(output));
824
1103
  if (looksLikeMissingWorkload(output)) printWorkloadHint();
825
1104
  else if (looksLikeMissingXcode(output)) printXcodeHint();
826
1105
  if (!this.verbose) {
827
- console.error(
828
- chalk6.dim(" Re-run with --verbose for the full build log.")
829
- );
1106
+ console.error(footer(dim("re-run with --verbose for the full build log.")));
830
1107
  }
831
1108
  process.exit(1);
832
1109
  }
@@ -837,9 +1114,12 @@ var DevSession = class {
837
1114
  );
838
1115
  if (!appBundle) {
839
1116
  console.error(
840
- chalk6.red(
841
- ` Could not find .app bundle in ${path6.join(this.project.hostDir, "bin", this.buildConfig, this.target.framework)}`
842
- )
1117
+ row({
1118
+ glyph: "error",
1119
+ detail: dim(
1120
+ `could not find .app bundle in ${path6.join(this.project.hostDir, "bin", this.buildConfig, this.target.framework)}`
1121
+ )
1122
+ })
843
1123
  );
844
1124
  process.exit(1);
845
1125
  }
@@ -851,11 +1131,16 @@ var DevSession = class {
851
1131
  const binary = findMacExecutable(appBundle);
852
1132
  if (!binary) {
853
1133
  console.error(
854
- chalk6.red(` Could not find the app executable in ${appBundle}.`)
1134
+ row({
1135
+ glyph: "error",
1136
+ detail: dim(`could not find the app executable in ${appBundle}`)
1137
+ })
855
1138
  );
856
1139
  process.exit(1);
857
1140
  }
858
- console.log(` ${chalk6.dim("Launching host...")}`);
1141
+ console.log(
1142
+ taggedRow("done", "host", `${dim("launched")} ${value(path6.basename(appBundle))}`)
1143
+ );
859
1144
  const host = spawn(binary, [], {
860
1145
  cwd: this.project.root,
861
1146
  stdio: ["ignore", "pipe", "pipe"],
@@ -864,7 +1149,7 @@ var DevSession = class {
864
1149
  return this.registerChild(host, "host", path6.basename(binary));
865
1150
  }
866
1151
  launchWindowsHost() {
867
- console.log(` ${chalk6.dim("Launching host...")}`);
1152
+ console.log(taggedRow("active", "host", dim("launching\u2026")));
868
1153
  const host = spawn(
869
1154
  DOTNET_COMMAND,
870
1155
  [
@@ -884,17 +1169,16 @@ var DevSession = class {
884
1169
  );
885
1170
  return this.registerChild(host, "host", "MAUI host");
886
1171
  }
887
- registerChild(child, tag, label) {
1172
+ registerChild(child, tag2, label) {
888
1173
  this.children.push(child);
889
- prefixStream(child.stdout, tag);
890
- prefixStream(child.stderr, tag);
1174
+ prefixStream(child.stdout, tag2);
1175
+ prefixStream(child.stderr, tag2);
891
1176
  child.on("exit", (code, signal) => {
892
1177
  if (this.shuttingDown) return;
893
- if (tag === "ui") {
1178
+ if (tag2 === "ui") {
894
1179
  const exitCode = code ?? 1;
895
1180
  console.error(
896
- chalk6.red(`
897
- ${label} exited with code ${exitCode}.`)
1181
+ "\n" + row({ glyph: "error", detail: dim(`${label} exited with code ${exitCode}`) })
898
1182
  );
899
1183
  this.shutdown(exitCode);
900
1184
  return;
@@ -902,12 +1186,14 @@ var DevSession = class {
902
1186
  const failed = code !== null && code !== 0 || signal !== null;
903
1187
  if (failed) {
904
1188
  console.error(
905
- chalk6.red(
906
- `
907
- ${label} exited with ${signal ? `signal ${signal}` : `code ${code}`}.`
908
- )
1189
+ "\n" + row({
1190
+ glyph: "error",
1191
+ detail: dim(
1192
+ `${label} exited with ${signal ? `signal ${signal}` : `code ${code}`}`
1193
+ )
1194
+ })
909
1195
  );
910
- if (tag === "host" && this.target.name === "macos") {
1196
+ if (tag2 === "host" && this.target.name === "macos") {
911
1197
  printMacLaunchHint();
912
1198
  }
913
1199
  }
@@ -915,9 +1201,10 @@ var DevSession = class {
915
1201
  });
916
1202
  child.on("error", (error) => {
917
1203
  if (this.shuttingDown) return;
918
- console.error(chalk6.red(`
919
- Failed to start ${label}: ${error.message}`));
920
- if (tag === "host" && this.target.name === "macos") {
1204
+ console.error(
1205
+ "\n" + row({ glyph: "error", detail: dim(`failed to start ${label}: ${error.message}`) })
1206
+ );
1207
+ if (tag2 === "host" && this.target.name === "macos") {
921
1208
  printMacLaunchHint();
922
1209
  }
923
1210
  this.shutdown(1);
@@ -935,23 +1222,26 @@ var DevSession = class {
935
1222
  };
936
1223
  var ensureTargetMatchesHostOs = (targetName) => {
937
1224
  if (targetName === "macos" && process.platform !== "darwin") {
938
- console.error(chalk6.red(" The macOS dev target can only run on macOS."));
1225
+ console.error(
1226
+ row({ glyph: "error", detail: dim("the macOS target can only run on macOS") })
1227
+ );
939
1228
  process.exit(1);
940
1229
  }
941
1230
  if (targetName === "windows" && process.platform !== "win32") {
942
1231
  console.error(
943
- chalk6.red(" The Windows dev target can only run on Windows.")
1232
+ row({ glyph: "error", detail: dim("the Windows target can only run on Windows") })
944
1233
  );
945
1234
  process.exit(1);
946
1235
  }
947
1236
  };
948
- var prefixStream = (stream, tag) => {
1237
+ var prefixStream = (stream, tag2) => {
949
1238
  if (!stream) return;
1239
+ const prefix = streamPrefix(tag2);
950
1240
  stream.on("data", (chunk) => {
951
1241
  const lines = chunk.toString().split("\n");
952
1242
  for (const line of lines) {
953
1243
  if (line.length > 0) {
954
- process.stdout.write(`\x1B[90m[${tag}]\x1B[0m ${line}
1244
+ process.stdout.write(`${prefix} ${line}
955
1245
  `);
956
1246
  }
957
1247
  }
@@ -1028,7 +1318,7 @@ var killChild = (child) => {
1028
1318
  if (!child.pid || child.exitCode !== null) return;
1029
1319
  if (process.platform === "win32") {
1030
1320
  try {
1031
- execFileSync3("taskkill", ["/PID", String(child.pid), "/T", "/F"], {
1321
+ execFileSync4("taskkill", ["/PID", String(child.pid), "/T", "/F"], {
1032
1322
  stdio: "ignore"
1033
1323
  });
1034
1324
  } catch {
@@ -1040,48 +1330,50 @@ var killChild = (child) => {
1040
1330
  };
1041
1331
  var printMacLaunchHint = () => {
1042
1332
  console.error();
1043
- console.error(chalk6.yellow(" The host built but the app couldn't launch."));
1044
1333
  console.error(
1045
- chalk6.dim(
1046
- " On macOS this is usually code signing / Gatekeeper for a locally built app:"
1334
+ row({ glyph: "manual", label: "the host built but the app couldn't launch." })
1335
+ );
1336
+ console.error(
1337
+ footer(
1338
+ dim(
1339
+ "on macOS this is usually code signing / Gatekeeper for a locally built app:"
1340
+ )
1047
1341
  )
1048
1342
  );
1049
1343
  console.error(
1050
- ` ${chalk6.dim("\u2022")} Install full Xcode, then run ${chalk6.cyan("vidra doctor")} to verify`
1344
+ ` ${dim("\u2022")} ${dim("install full Xcode, then run")} ${lime("vidra doctor")} ${dim("to verify")}`
1051
1345
  );
1052
1346
  console.error(
1053
- ` ${chalk6.dim("\u2022")} Approve it once in Finder: right-click the ${chalk6.cyan(".app")} and choose ${chalk6.cyan("Open")}`
1347
+ ` ${dim("\u2022")} ${dim("approve it once in Finder: right-click the")} ${value(".app")} ${dim("and choose")} ${value("Open")}`
1054
1348
  );
1055
1349
  console.error(
1056
- ` ${chalk6.dim("\u2022")} Or provide a signing identity via ${chalk6.cyan("VIDRA_MACOS_CODESIGN_KEY")}`
1350
+ ` ${dim("\u2022")} ${dim("or provide a signing identity via")} ${value("VIDRA_MACOS_CODESIGN_KEY")}`
1057
1351
  );
1058
1352
  console.error();
1059
1353
  };
1060
1354
 
1061
1355
  // src/cli.ts
1062
- var VERSION3 = "0.1.5";
1063
1356
  var printHelp = () => {
1357
+ const cmd = (name, desc) => ` ${value(name.padEnd(10))} ${dim(desc)}`;
1358
+ const ex = (args, comment) => ` ${lime("vidra")} ${value(args.padEnd(22))} ${dim(`# ${comment}`)}`;
1064
1359
  console.log(`
1065
- ${chalk7.bold("vidra")} ${chalk7.dim(`v${VERSION3}`)}
1360
+ ${wordmark()} ${dim(`v${CLI_VERSION}`)}
1066
1361
 
1067
- ${chalk7.dim("Usage:")}
1068
- vidra <command> [options]
1362
+ ${dim("usage")}
1363
+ ${lime("vidra")} ${dim("<command> [options]")}
1069
1364
 
1070
- ${chalk7.dim("Commands:")}
1071
- dev Start the development environment (Vite + native host)
1072
- run Build and launch the native host only (no Vite dev server)
1073
- build Build and package the application for distribution
1074
- doctor Check that your environment is set up to build Vidra apps
1075
- help Show this help message
1365
+ ${dim("commands")}
1366
+ ${cmd("dev", "start vite + the native host (hot reload)")}
1367
+ ${cmd("run", "launch the native host only")}
1368
+ ${cmd("build", "build & package for distribution")}
1369
+ ${cmd("doctor", "check your environment")}
1370
+ ${cmd("help", "show this message")}
1076
1371
 
1077
- ${chalk7.dim("Examples:")}
1078
- vidra dev ${chalk7.dim("# start Vite + native host")}
1079
- vidra dev --target windows ${chalk7.dim("# run the Windows host")}
1080
- vidra run ${chalk7.dim("# launch the host (UI served separately)")}
1081
- vidra build ${chalk7.dim("# auto-detect platform")}
1082
- vidra build --target macos ${chalk7.dim("# macOS DMG")}
1083
- vidra build --verbose ${chalk7.dim("# show full build output")}
1084
- vidra doctor ${chalk7.dim("# verify .NET SDK + MAUI workload")}
1372
+ ${dim("examples")}
1373
+ ${ex("dev --target windows", "run the windows host")}
1374
+ ${ex("build --plan", "preview the build, run nothing")}
1375
+ ${ex("build --target macos", "build & package a macOS DMG")}
1376
+ ${ex("doctor", "verify .NET SDK + MAUI workload")}
1085
1377
  `);
1086
1378
  };
1087
1379
  var main = async () => {
@@ -1108,16 +1400,15 @@ var main = async () => {
1108
1400
  break;
1109
1401
  case "--version":
1110
1402
  case "-v":
1111
- console.log(VERSION3);
1403
+ console.log(CLI_VERSION);
1112
1404
  break;
1113
1405
  default:
1114
- console.error(chalk7.red(` Unknown command: ${command}
1115
- `));
1406
+ console.error(row({ glyph: "error", detail: dim(`unknown command: ${command}`) }));
1116
1407
  printHelp();
1117
1408
  process.exit(1);
1118
1409
  }
1119
1410
  };
1120
1411
  main().catch((e) => {
1121
- console.error(chalk7.red(e.message));
1412
+ console.error(row({ glyph: "error", detail: dim(e.message) }));
1122
1413
  process.exit(1);
1123
1414
  });