gistajs 0.0.9 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.cjs CHANGED
@@ -56,6 +56,46 @@ function parseStarter(data) {
56
56
  return { slug, repo, branches, description };
57
57
  }
58
58
 
59
+ // src/color.ts
60
+ var import_picocolors = __toESM(require("picocolors"), 1);
61
+ var c = {
62
+ brand: (s) => import_picocolors.default.bold(import_picocolors.default.cyan(s)),
63
+ success: (s) => import_picocolors.default.bold(s),
64
+ path: (s) => import_picocolors.default.underline(s),
65
+ slug: (s) => import_picocolors.default.cyan(s),
66
+ prompt: (s) => import_picocolors.default.bold(import_picocolors.default.yellow(s)),
67
+ error: (s) => import_picocolors.default.red(s),
68
+ errorLabel: (s) => import_picocolors.default.bold(import_picocolors.default.red(s)),
69
+ dim: (s) => import_picocolors.default.dim(s),
70
+ bold: (s) => import_picocolors.default.bold(s)
71
+ };
72
+ var LOGO = [
73
+ " ____ _ _ _ ",
74
+ " / ___(_)___| |_ __ _ (_)___ ",
75
+ " | | _| / __| __/ _` | | / __|",
76
+ " | |_| | \\__ \\ || (_| |_ | \\__ \\",
77
+ " \\____|_|___/\\__\\__,_(_)/ |___/",
78
+ " |__/ "
79
+ ];
80
+ function lerp(a, b, t) {
81
+ return Math.round(a + (b - a) * t);
82
+ }
83
+ function rgb(r, g, b, text) {
84
+ return `\x1B[38;2;${r};${g};${b}m${text}\x1B[39m`;
85
+ }
86
+ function logo() {
87
+ let from = [0, 255, 65];
88
+ let to = [0, 143, 17];
89
+ let total = LOGO.length;
90
+ return LOGO.map((line, i) => {
91
+ let t = total <= 1 ? 0 : i / (total - 1);
92
+ let r = lerp(from[0], to[0], t);
93
+ let g = lerp(from[1], to[1], t);
94
+ let b = lerp(from[2], to[2], t);
95
+ return rgb(r, g, b, line);
96
+ }).join("\n");
97
+ }
98
+
59
99
  // src/create.ts
60
100
  var import_promises2 = require("fs/promises");
61
101
  var import_node_os = require("os");
@@ -73,11 +113,13 @@ async function promptForStarter(starters) {
73
113
  let rl = createPrompt();
74
114
  try {
75
115
  let options = starters.map(
76
- (starter2, index2) => `${index2 + 1}. ${starter2.slug} - ${starter2.description}`
116
+ (starter2, index2) => ` ${c.dim(`${index2 + 1}.`)} ${c.slug(starter2.slug)} ${c.dim("\u2014")} ${starter2.description}`
77
117
  ).join("\n");
78
- let answer = await rl.question(`Choose a starter:
118
+ let answer = await rl.question(
119
+ `${c.prompt("Choose a starter:")}
79
120
  ${options}
80
- > `);
121
+ ${c.dim(">")} `
122
+ );
81
123
  let index = Number.parseInt(answer.trim(), 10) - 1;
82
124
  let starter = starters[index];
83
125
  if (!starter) throw new Error("Invalid starter selection");
@@ -90,10 +132,12 @@ async function promptForGitIdentity() {
90
132
  let rl = createPrompt();
91
133
  try {
92
134
  console.log(
93
- "Before I make the first commit, Git needs a name and email to attach to it."
135
+ c.dim(
136
+ "Before I make the first commit, Git needs a name and email to attach to it."
137
+ )
94
138
  );
95
- let name = (await rl.question("Your name: ")).trim();
96
- let email = (await rl.question("Your email: ")).trim();
139
+ let name = (await rl.question(c.prompt("Your name: "))).trim();
140
+ let email = (await rl.question(c.prompt("Your email: "))).trim();
97
141
  if (!name) throw new Error("Name is required to make the first commit");
98
142
  if (!email) throw new Error("Email is required to make the first commit");
99
143
  let saveGlobal = await confirm(
@@ -105,6 +149,16 @@ async function promptForGitIdentity() {
105
149
  rl.close();
106
150
  }
107
151
  }
152
+ async function promptConfirm(message, defaultYes = true) {
153
+ let rl = createPrompt();
154
+ try {
155
+ let answer = (await rl.question(c.prompt(message))).trim().toLowerCase();
156
+ if (answer === "") return defaultYes;
157
+ return answer === "y" || answer === "yes";
158
+ } finally {
159
+ rl.close();
160
+ }
161
+ }
108
162
  function createPrompt() {
109
163
  return import_promises.default.createInterface({
110
164
  input: import_node_process.default.stdin,
@@ -112,7 +166,7 @@ function createPrompt() {
112
166
  });
113
167
  }
114
168
  async function confirm(rl, message) {
115
- let answer = (await rl.question(message)).trim().toLowerCase();
169
+ let answer = (await rl.question(c.dim(message))).trim().toLowerCase();
116
170
  return answer === "y" || answer === "yes";
117
171
  }
118
172
 
@@ -128,7 +182,9 @@ async function run(command, args, cwd) {
128
182
  child.once("exit", (code) => {
129
183
  if (code === 0) resolve2();
130
184
  else {
131
- reject(new Error(`${command} ${args.join(" ")} exited with code ${code}`));
185
+ reject(
186
+ new Error(`${command} ${args.join(" ")} exited with code ${code}`)
187
+ );
132
188
  }
133
189
  });
134
190
  });
@@ -340,12 +396,10 @@ async function diffStarter(starter, options, deps = defaultDeps2) {
340
396
  await git2(root, ["remote", "add", "origin", repoUrl], deps);
341
397
  await fetchTag(root, fromTag, repoUrl, deps);
342
398
  await fetchTag(root, toTag, repoUrl, deps);
343
- return await gitOutput(
344
- root,
345
- ["diff", "--stat", `refs/tags/${fromTag}`, `refs/tags/${toTag}`],
346
- repoUrl,
347
- deps
348
- );
399
+ let diffArgs = ["diff"];
400
+ if (options.stat) diffArgs.push("--stat");
401
+ diffArgs.push(`refs/tags/${fromTag}`, `refs/tags/${toTag}`);
402
+ return await gitOutput(root, diffArgs, repoUrl, deps);
349
403
  } finally {
350
404
  await deps.rm(root, { recursive: true, force: true });
351
405
  }
@@ -360,7 +414,13 @@ async function fetchTag(cwd, tag, repoUrl, deps) {
360
414
  try {
361
415
  await git2(
362
416
  cwd,
363
- ["fetch", "--quiet", "--no-tags", "origin", `refs/tags/${tag}:refs/tags/${tag}`],
417
+ [
418
+ "fetch",
419
+ "--quiet",
420
+ "--no-tags",
421
+ "origin",
422
+ `refs/tags/${tag}:refs/tags/${tag}`
423
+ ],
364
424
  deps
365
425
  );
366
426
  } catch (error) {
@@ -420,12 +480,15 @@ var defaultDeps3 = {
420
480
  createProject,
421
481
  diffStarter,
422
482
  promptForStarter,
483
+ promptConfirm,
423
484
  stdout: console
424
485
  };
425
486
  var UsageError = class extends Error {
426
- constructor(message) {
487
+ command;
488
+ constructor(message, command) {
427
489
  super(message);
428
490
  this.name = "UsageError";
491
+ this.command = command;
429
492
  }
430
493
  };
431
494
  async function runCli(argv = import_node_process3.default.argv.slice(2), deps = defaultDeps3) {
@@ -434,36 +497,50 @@ async function runCli(argv = import_node_process3.default.argv.slice(2), deps =
434
497
  deps.stdout.log(getHelpText());
435
498
  return;
436
499
  }
500
+ if (command === "logo") {
501
+ deps.stdout.log("\n" + logo() + "\n");
502
+ return;
503
+ }
437
504
  if (command === "create") {
438
505
  let options = parseCreateArgs(rest);
439
506
  if (!options.projectName) {
440
- throw new UsageError("Project name is required");
507
+ throw new UsageError("Project name is required", "create");
441
508
  }
442
509
  let catalog = await deps.loadCatalog(options.catalogUrl);
443
510
  let starterName = options.starter || await deps.promptForStarter(catalog);
444
511
  let starter = catalog.find((entry) => entry.slug === starterName);
445
512
  if (!starter) {
446
- throw new UsageError(`Unknown starter: ${starterName}`);
513
+ throw new UsageError(`Unknown starter: ${starterName}`, "create");
514
+ }
515
+ if (options.git === void 0) {
516
+ options.git = await deps.promptConfirm("Initialize git? (Y/n) ");
517
+ }
518
+ if (options.install === void 0) {
519
+ options.install = await deps.promptConfirm("Install dependencies? (Y/n) ");
447
520
  }
448
521
  let root = await deps.createProject(starter, options);
449
- deps.stdout.log(`Created ${starter.slug} project in ${root}`);
522
+ deps.stdout.log(
523
+ `
524
+ ${c.brand("gistajs")} ${c.success("Created")} ${c.slug(starter.slug)} project in ${c.path(root)}
525
+ `
526
+ );
450
527
  return;
451
528
  }
452
529
  if (command === "diff") {
453
530
  let options = parseDiffArgs(rest);
454
531
  if (!options.starter) {
455
- throw new UsageError("Starter is required");
532
+ throw new UsageError("Starter is required", "diff");
456
533
  }
457
534
  if (!options.fromReleaseKey) {
458
- throw new UsageError("From release key is required");
535
+ throw new UsageError("From release key is required", "diff");
459
536
  }
460
537
  if (!options.toReleaseKey) {
461
- throw new UsageError("To release key is required");
538
+ throw new UsageError("To release key is required", "diff");
462
539
  }
463
540
  let catalog = await deps.loadCatalog(options.catalogUrl);
464
541
  let starter = catalog.find((entry) => entry.slug === options.starter);
465
542
  if (!starter) {
466
- throw new UsageError(`Unknown starter: ${options.starter}`);
543
+ throw new UsageError(`Unknown starter: ${options.starter}`, "diff");
467
544
  }
468
545
  let output = await deps.diffStarter(starter, options);
469
546
  deps.stdout.log(output.trimEnd());
@@ -476,18 +553,15 @@ async function main() {
476
553
  await runCli();
477
554
  } catch (error) {
478
555
  let message = error instanceof Error ? error.message : String(error);
479
- console.error(message);
556
+ console.error(`${c.errorLabel("error:")} ${c.error(message)}`);
480
557
  if (error instanceof UsageError) {
481
- console.error(getHelpText());
558
+ console.error(getHelpText(error.command));
482
559
  }
483
560
  import_node_process3.default.exitCode = 1;
484
561
  }
485
562
  }
486
563
  function parseCreateArgs(argv) {
487
- let options = {
488
- install: true,
489
- git: true
490
- };
564
+ let options = {};
491
565
  for (let index = 0; index < argv.length; index += 1) {
492
566
  let arg = argv[index];
493
567
  if (!arg) continue;
@@ -496,7 +570,8 @@ function parseCreateArgs(argv) {
496
570
  continue;
497
571
  }
498
572
  if (arg === "--starter") {
499
- if (!argv[index + 1]) throw new UsageError("--starter requires a value");
573
+ if (!argv[index + 1])
574
+ throw new UsageError("--starter requires a value", "create");
500
575
  options.starter = argv[index + 1];
501
576
  index += 1;
502
577
  continue;
@@ -511,13 +586,13 @@ function parseCreateArgs(argv) {
511
586
  }
512
587
  if (arg === "--catalog-url") {
513
588
  if (!argv[index + 1]) {
514
- throw new UsageError("--catalog-url requires a value");
589
+ throw new UsageError("--catalog-url requires a value", "create");
515
590
  }
516
591
  options.catalogUrl = argv[index + 1];
517
592
  index += 1;
518
593
  continue;
519
594
  }
520
- throw new UsageError(`Unknown argument: ${arg}`);
595
+ throw new UsageError(`Unknown argument: ${arg}`, "create");
521
596
  }
522
597
  return options;
523
598
  }
@@ -538,30 +613,66 @@ function parseDiffArgs(argv) {
538
613
  options.toReleaseKey = arg;
539
614
  continue;
540
615
  }
616
+ if (arg === "--stat") {
617
+ options.stat = true;
618
+ continue;
619
+ }
541
620
  if (arg === "--catalog-url") {
542
621
  if (!argv[index + 1]) {
543
- throw new UsageError("--catalog-url requires a value");
622
+ throw new UsageError("--catalog-url requires a value", "diff");
544
623
  }
545
624
  options.catalogUrl = argv[index + 1];
546
625
  index += 1;
547
626
  continue;
548
627
  }
549
- throw new UsageError(`Unknown argument: ${arg}`);
628
+ throw new UsageError(`Unknown argument: ${arg}`, "diff");
550
629
  }
551
630
  return options;
552
631
  }
553
- function getHelpText() {
632
+ function getHelpText(command) {
633
+ let header = ` ${c.brand("gistajs")} ${c.dim("\u2014 scaffold Gista.js starter projects")}`;
634
+ if (command === "create") {
635
+ return [
636
+ "",
637
+ header,
638
+ "",
639
+ ` ${c.bold("Usage:")}`,
640
+ ` ${c.dim("$")} ${c.bold("gistajs create")} <project-name> [--starter <slug>] [--no-install] [--no-git]`,
641
+ "",
642
+ ` ${c.bold("Examples:")}`,
643
+ ` ${c.dim("$")} gistajs create my-app`,
644
+ ` ${c.dim("$")} gistajs create my-app --starter website`,
645
+ ""
646
+ ].join("\n");
647
+ }
648
+ if (command === "diff") {
649
+ return [
650
+ "",
651
+ header,
652
+ "",
653
+ ` ${c.bold("Usage:")}`,
654
+ ` ${c.dim("$")} ${c.bold("gistajs diff")} <starter> <from-release-key> <to-release-key> [--stat]`,
655
+ "",
656
+ ` ${c.bold("Examples:")}`,
657
+ ` ${c.dim("$")} gistajs diff auth 2026-03-28-001 2026-03-29-001`,
658
+ ` ${c.dim("$")} gistajs diff auth 2026-03-28-001 2026-03-29-001 --stat`,
659
+ ""
660
+ ].join("\n");
661
+ }
554
662
  return [
555
- "Usage:",
556
- " gistajs create <project-name> [--starter <slug>] [--no-install] [--no-git]",
557
- " gistajs diff <starter> <from-release-key> <to-release-key>",
558
663
  "",
559
- "Examples:",
560
- " gistajs create my-app",
561
- " gistajs create my-app --starter website",
562
- " gistajs diff auth 2026-03-28-001 2026-03-29-001",
664
+ header,
665
+ "",
666
+ ` ${c.bold("Usage:")}`,
667
+ ` ${c.dim("$")} ${c.bold("gistajs create")} <project-name> [--starter <slug>] [--no-install] [--no-git]`,
668
+ ` ${c.dim("$")} ${c.bold("gistajs diff")} <starter> <from-release-key> <to-release-key> [--stat]`,
563
669
  "",
564
- "Run `gistajs` with no arguments to show this help."
670
+ ` ${c.bold("Examples:")}`,
671
+ ` ${c.dim("$")} gistajs create my-app`,
672
+ ` ${c.dim("$")} gistajs create my-app --starter website`,
673
+ ` ${c.dim("$")} gistajs diff auth 2026-03-28-001 2026-03-29-001`,
674
+ ` ${c.dim("$")} gistajs diff auth 2026-03-28-001 2026-03-29-001 --stat`,
675
+ ""
565
676
  ].join("\n");
566
677
  }
567
678
 
package/dist/index.d.ts CHANGED
@@ -18,6 +18,7 @@ type DiffOptions = {
18
18
  starter?: string;
19
19
  fromReleaseKey?: string;
20
20
  toReleaseKey?: string;
21
+ stat?: boolean;
21
22
  catalogUrl?: string;
22
23
  };
23
24
 
@@ -37,12 +38,14 @@ declare function diffStarter(starter: StarterSpec, options: DiffOptions, deps?:
37
38
  declare function runOutput(command: string, args: string[], cwd: string): Promise<string>;
38
39
 
39
40
  declare function promptForStarter(starters: StarterSpec[]): Promise<string>;
41
+ declare function promptConfirm(message: string, defaultYes?: boolean): Promise<boolean>;
40
42
 
41
43
  type CliDeps = {
42
44
  loadCatalog: typeof loadCatalog;
43
45
  createProject: typeof createProject;
44
46
  diffStarter: typeof diffStarter;
45
47
  promptForStarter: typeof promptForStarter;
48
+ promptConfirm: typeof promptConfirm;
46
49
  stdout: Pick<typeof console, 'log'>;
47
50
  };
48
51
  declare function runCli(argv?: string[], deps?: CliDeps): Promise<void>;
package/dist/index.js CHANGED
@@ -31,6 +31,46 @@ function parseStarter(data) {
31
31
  return { slug, repo, branches, description };
32
32
  }
33
33
 
34
+ // src/color.ts
35
+ import pc from "picocolors";
36
+ var c = {
37
+ brand: (s) => pc.bold(pc.cyan(s)),
38
+ success: (s) => pc.bold(s),
39
+ path: (s) => pc.underline(s),
40
+ slug: (s) => pc.cyan(s),
41
+ prompt: (s) => pc.bold(pc.yellow(s)),
42
+ error: (s) => pc.red(s),
43
+ errorLabel: (s) => pc.bold(pc.red(s)),
44
+ dim: (s) => pc.dim(s),
45
+ bold: (s) => pc.bold(s)
46
+ };
47
+ var LOGO = [
48
+ " ____ _ _ _ ",
49
+ " / ___(_)___| |_ __ _ (_)___ ",
50
+ " | | _| / __| __/ _` | | / __|",
51
+ " | |_| | \\__ \\ || (_| |_ | \\__ \\",
52
+ " \\____|_|___/\\__\\__,_(_)/ |___/",
53
+ " |__/ "
54
+ ];
55
+ function lerp(a, b, t) {
56
+ return Math.round(a + (b - a) * t);
57
+ }
58
+ function rgb(r, g, b, text) {
59
+ return `\x1B[38;2;${r};${g};${b}m${text}\x1B[39m`;
60
+ }
61
+ function logo() {
62
+ let from = [0, 255, 65];
63
+ let to = [0, 143, 17];
64
+ let total = LOGO.length;
65
+ return LOGO.map((line, i) => {
66
+ let t = total <= 1 ? 0 : i / (total - 1);
67
+ let r = lerp(from[0], to[0], t);
68
+ let g = lerp(from[1], to[1], t);
69
+ let b = lerp(from[2], to[2], t);
70
+ return rgb(r, g, b, line);
71
+ }).join("\n");
72
+ }
73
+
34
74
  // src/create.ts
35
75
  import {
36
76
  cp,
@@ -58,11 +98,13 @@ async function promptForStarter(starters) {
58
98
  let rl = createPrompt();
59
99
  try {
60
100
  let options = starters.map(
61
- (starter2, index2) => `${index2 + 1}. ${starter2.slug} - ${starter2.description}`
101
+ (starter2, index2) => ` ${c.dim(`${index2 + 1}.`)} ${c.slug(starter2.slug)} ${c.dim("\u2014")} ${starter2.description}`
62
102
  ).join("\n");
63
- let answer = await rl.question(`Choose a starter:
103
+ let answer = await rl.question(
104
+ `${c.prompt("Choose a starter:")}
64
105
  ${options}
65
- > `);
106
+ ${c.dim(">")} `
107
+ );
66
108
  let index = Number.parseInt(answer.trim(), 10) - 1;
67
109
  let starter = starters[index];
68
110
  if (!starter) throw new Error("Invalid starter selection");
@@ -75,10 +117,12 @@ async function promptForGitIdentity() {
75
117
  let rl = createPrompt();
76
118
  try {
77
119
  console.log(
78
- "Before I make the first commit, Git needs a name and email to attach to it."
120
+ c.dim(
121
+ "Before I make the first commit, Git needs a name and email to attach to it."
122
+ )
79
123
  );
80
- let name = (await rl.question("Your name: ")).trim();
81
- let email = (await rl.question("Your email: ")).trim();
124
+ let name = (await rl.question(c.prompt("Your name: "))).trim();
125
+ let email = (await rl.question(c.prompt("Your email: "))).trim();
82
126
  if (!name) throw new Error("Name is required to make the first commit");
83
127
  if (!email) throw new Error("Email is required to make the first commit");
84
128
  let saveGlobal = await confirm(
@@ -90,6 +134,16 @@ async function promptForGitIdentity() {
90
134
  rl.close();
91
135
  }
92
136
  }
137
+ async function promptConfirm(message, defaultYes = true) {
138
+ let rl = createPrompt();
139
+ try {
140
+ let answer = (await rl.question(c.prompt(message))).trim().toLowerCase();
141
+ if (answer === "") return defaultYes;
142
+ return answer === "y" || answer === "yes";
143
+ } finally {
144
+ rl.close();
145
+ }
146
+ }
93
147
  function createPrompt() {
94
148
  return readline.createInterface({
95
149
  input: process.stdin,
@@ -97,7 +151,7 @@ function createPrompt() {
97
151
  });
98
152
  }
99
153
  async function confirm(rl, message) {
100
- let answer = (await rl.question(message)).trim().toLowerCase();
154
+ let answer = (await rl.question(c.dim(message))).trim().toLowerCase();
101
155
  return answer === "y" || answer === "yes";
102
156
  }
103
157
 
@@ -113,7 +167,9 @@ async function run(command, args, cwd) {
113
167
  child.once("exit", (code) => {
114
168
  if (code === 0) resolve2();
115
169
  else {
116
- reject(new Error(`${command} ${args.join(" ")} exited with code ${code}`));
170
+ reject(
171
+ new Error(`${command} ${args.join(" ")} exited with code ${code}`)
172
+ );
117
173
  }
118
174
  });
119
175
  });
@@ -325,12 +381,10 @@ async function diffStarter(starter, options, deps = defaultDeps2) {
325
381
  await git2(root, ["remote", "add", "origin", repoUrl], deps);
326
382
  await fetchTag(root, fromTag, repoUrl, deps);
327
383
  await fetchTag(root, toTag, repoUrl, deps);
328
- return await gitOutput(
329
- root,
330
- ["diff", "--stat", `refs/tags/${fromTag}`, `refs/tags/${toTag}`],
331
- repoUrl,
332
- deps
333
- );
384
+ let diffArgs = ["diff"];
385
+ if (options.stat) diffArgs.push("--stat");
386
+ diffArgs.push(`refs/tags/${fromTag}`, `refs/tags/${toTag}`);
387
+ return await gitOutput(root, diffArgs, repoUrl, deps);
334
388
  } finally {
335
389
  await deps.rm(root, { recursive: true, force: true });
336
390
  }
@@ -345,7 +399,13 @@ async function fetchTag(cwd, tag, repoUrl, deps) {
345
399
  try {
346
400
  await git2(
347
401
  cwd,
348
- ["fetch", "--quiet", "--no-tags", "origin", `refs/tags/${tag}:refs/tags/${tag}`],
402
+ [
403
+ "fetch",
404
+ "--quiet",
405
+ "--no-tags",
406
+ "origin",
407
+ `refs/tags/${tag}:refs/tags/${tag}`
408
+ ],
349
409
  deps
350
410
  );
351
411
  } catch (error) {
@@ -405,12 +465,15 @@ var defaultDeps3 = {
405
465
  createProject,
406
466
  diffStarter,
407
467
  promptForStarter,
468
+ promptConfirm,
408
469
  stdout: console
409
470
  };
410
471
  var UsageError = class extends Error {
411
- constructor(message) {
472
+ command;
473
+ constructor(message, command) {
412
474
  super(message);
413
475
  this.name = "UsageError";
476
+ this.command = command;
414
477
  }
415
478
  };
416
479
  async function runCli(argv = process3.argv.slice(2), deps = defaultDeps3) {
@@ -419,36 +482,50 @@ async function runCli(argv = process3.argv.slice(2), deps = defaultDeps3) {
419
482
  deps.stdout.log(getHelpText());
420
483
  return;
421
484
  }
485
+ if (command === "logo") {
486
+ deps.stdout.log("\n" + logo() + "\n");
487
+ return;
488
+ }
422
489
  if (command === "create") {
423
490
  let options = parseCreateArgs(rest);
424
491
  if (!options.projectName) {
425
- throw new UsageError("Project name is required");
492
+ throw new UsageError("Project name is required", "create");
426
493
  }
427
494
  let catalog = await deps.loadCatalog(options.catalogUrl);
428
495
  let starterName = options.starter || await deps.promptForStarter(catalog);
429
496
  let starter = catalog.find((entry) => entry.slug === starterName);
430
497
  if (!starter) {
431
- throw new UsageError(`Unknown starter: ${starterName}`);
498
+ throw new UsageError(`Unknown starter: ${starterName}`, "create");
499
+ }
500
+ if (options.git === void 0) {
501
+ options.git = await deps.promptConfirm("Initialize git? (Y/n) ");
502
+ }
503
+ if (options.install === void 0) {
504
+ options.install = await deps.promptConfirm("Install dependencies? (Y/n) ");
432
505
  }
433
506
  let root = await deps.createProject(starter, options);
434
- deps.stdout.log(`Created ${starter.slug} project in ${root}`);
507
+ deps.stdout.log(
508
+ `
509
+ ${c.brand("gistajs")} ${c.success("Created")} ${c.slug(starter.slug)} project in ${c.path(root)}
510
+ `
511
+ );
435
512
  return;
436
513
  }
437
514
  if (command === "diff") {
438
515
  let options = parseDiffArgs(rest);
439
516
  if (!options.starter) {
440
- throw new UsageError("Starter is required");
517
+ throw new UsageError("Starter is required", "diff");
441
518
  }
442
519
  if (!options.fromReleaseKey) {
443
- throw new UsageError("From release key is required");
520
+ throw new UsageError("From release key is required", "diff");
444
521
  }
445
522
  if (!options.toReleaseKey) {
446
- throw new UsageError("To release key is required");
523
+ throw new UsageError("To release key is required", "diff");
447
524
  }
448
525
  let catalog = await deps.loadCatalog(options.catalogUrl);
449
526
  let starter = catalog.find((entry) => entry.slug === options.starter);
450
527
  if (!starter) {
451
- throw new UsageError(`Unknown starter: ${options.starter}`);
528
+ throw new UsageError(`Unknown starter: ${options.starter}`, "diff");
452
529
  }
453
530
  let output = await deps.diffStarter(starter, options);
454
531
  deps.stdout.log(output.trimEnd());
@@ -457,10 +534,7 @@ async function runCli(argv = process3.argv.slice(2), deps = defaultDeps3) {
457
534
  throw new UsageError(`Unknown command: ${command}`);
458
535
  }
459
536
  function parseCreateArgs(argv) {
460
- let options = {
461
- install: true,
462
- git: true
463
- };
537
+ let options = {};
464
538
  for (let index = 0; index < argv.length; index += 1) {
465
539
  let arg = argv[index];
466
540
  if (!arg) continue;
@@ -469,7 +543,8 @@ function parseCreateArgs(argv) {
469
543
  continue;
470
544
  }
471
545
  if (arg === "--starter") {
472
- if (!argv[index + 1]) throw new UsageError("--starter requires a value");
546
+ if (!argv[index + 1])
547
+ throw new UsageError("--starter requires a value", "create");
473
548
  options.starter = argv[index + 1];
474
549
  index += 1;
475
550
  continue;
@@ -484,13 +559,13 @@ function parseCreateArgs(argv) {
484
559
  }
485
560
  if (arg === "--catalog-url") {
486
561
  if (!argv[index + 1]) {
487
- throw new UsageError("--catalog-url requires a value");
562
+ throw new UsageError("--catalog-url requires a value", "create");
488
563
  }
489
564
  options.catalogUrl = argv[index + 1];
490
565
  index += 1;
491
566
  continue;
492
567
  }
493
- throw new UsageError(`Unknown argument: ${arg}`);
568
+ throw new UsageError(`Unknown argument: ${arg}`, "create");
494
569
  }
495
570
  return options;
496
571
  }
@@ -511,30 +586,66 @@ function parseDiffArgs(argv) {
511
586
  options.toReleaseKey = arg;
512
587
  continue;
513
588
  }
589
+ if (arg === "--stat") {
590
+ options.stat = true;
591
+ continue;
592
+ }
514
593
  if (arg === "--catalog-url") {
515
594
  if (!argv[index + 1]) {
516
- throw new UsageError("--catalog-url requires a value");
595
+ throw new UsageError("--catalog-url requires a value", "diff");
517
596
  }
518
597
  options.catalogUrl = argv[index + 1];
519
598
  index += 1;
520
599
  continue;
521
600
  }
522
- throw new UsageError(`Unknown argument: ${arg}`);
601
+ throw new UsageError(`Unknown argument: ${arg}`, "diff");
523
602
  }
524
603
  return options;
525
604
  }
526
- function getHelpText() {
605
+ function getHelpText(command) {
606
+ let header = ` ${c.brand("gistajs")} ${c.dim("\u2014 scaffold Gista.js starter projects")}`;
607
+ if (command === "create") {
608
+ return [
609
+ "",
610
+ header,
611
+ "",
612
+ ` ${c.bold("Usage:")}`,
613
+ ` ${c.dim("$")} ${c.bold("gistajs create")} <project-name> [--starter <slug>] [--no-install] [--no-git]`,
614
+ "",
615
+ ` ${c.bold("Examples:")}`,
616
+ ` ${c.dim("$")} gistajs create my-app`,
617
+ ` ${c.dim("$")} gistajs create my-app --starter website`,
618
+ ""
619
+ ].join("\n");
620
+ }
621
+ if (command === "diff") {
622
+ return [
623
+ "",
624
+ header,
625
+ "",
626
+ ` ${c.bold("Usage:")}`,
627
+ ` ${c.dim("$")} ${c.bold("gistajs diff")} <starter> <from-release-key> <to-release-key> [--stat]`,
628
+ "",
629
+ ` ${c.bold("Examples:")}`,
630
+ ` ${c.dim("$")} gistajs diff auth 2026-03-28-001 2026-03-29-001`,
631
+ ` ${c.dim("$")} gistajs diff auth 2026-03-28-001 2026-03-29-001 --stat`,
632
+ ""
633
+ ].join("\n");
634
+ }
527
635
  return [
528
- "Usage:",
529
- " gistajs create <project-name> [--starter <slug>] [--no-install] [--no-git]",
530
- " gistajs diff <starter> <from-release-key> <to-release-key>",
531
636
  "",
532
- "Examples:",
533
- " gistajs create my-app",
534
- " gistajs create my-app --starter website",
535
- " gistajs diff auth 2026-03-28-001 2026-03-29-001",
637
+ header,
638
+ "",
639
+ ` ${c.bold("Usage:")}`,
640
+ ` ${c.dim("$")} ${c.bold("gistajs create")} <project-name> [--starter <slug>] [--no-install] [--no-git]`,
641
+ ` ${c.dim("$")} ${c.bold("gistajs diff")} <starter> <from-release-key> <to-release-key> [--stat]`,
536
642
  "",
537
- "Run `gistajs` with no arguments to show this help."
643
+ ` ${c.bold("Examples:")}`,
644
+ ` ${c.dim("$")} gistajs create my-app`,
645
+ ` ${c.dim("$")} gistajs create my-app --starter website`,
646
+ ` ${c.dim("$")} gistajs diff auth 2026-03-28-001 2026-03-29-001`,
647
+ ` ${c.dim("$")} gistajs diff auth 2026-03-28-001 2026-03-29-001 --stat`,
648
+ ""
538
649
  ].join("\n");
539
650
  }
540
651
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gistajs",
3
- "version": "0.0.9",
3
+ "version": "0.1.0",
4
4
  "description": "Create Gista.js starter projects",
5
5
  "keywords": [
6
6
  "cli",
@@ -33,7 +33,8 @@
33
33
  }
34
34
  },
35
35
  "dependencies": {
36
- "tar": "^7.5.1"
36
+ "picocolors": "^1.1.1",
37
+ "tar": "^7.5.13"
37
38
  },
38
39
  "devDependencies": {
39
40
  "@types/node": "^25.5.0",
@@ -41,7 +42,7 @@
41
42
  "oxfmt": "^0.40.0",
42
43
  "tsup": "^8.5.1",
43
44
  "typescript": "^5.9.3",
44
- "vitest": "^4.1.0"
45
+ "vitest": "^4.1.2"
45
46
  },
46
47
  "engines": {
47
48
  "node": ">=20"