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 +154 -43
- package/dist/index.d.ts +3 -0
- package/dist/index.js +152 -41
- package/package.json +4 -3
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}
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
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
|
-
[
|
|
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
|
-
|
|
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(
|
|
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])
|
|
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
|
-
|
|
560
|
-
"
|
|
561
|
-
|
|
562
|
-
"
|
|
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
|
-
|
|
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}
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
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
|
-
[
|
|
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
|
-
|
|
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(
|
|
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])
|
|
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
|
-
|
|
533
|
-
"
|
|
534
|
-
|
|
535
|
-
"
|
|
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
|
-
|
|
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
|
|
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
|
-
"
|
|
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.
|
|
45
|
+
"vitest": "^4.1.2"
|
|
45
46
|
},
|
|
46
47
|
"engines": {
|
|
47
48
|
"node": ">=20"
|