@apex-stack/core 0.1.9 → 0.1.10
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 +158 -46
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -418,11 +418,100 @@ var migrateCommand = defineCommand4({
|
|
|
418
418
|
});
|
|
419
419
|
|
|
420
420
|
// src/commands/new.ts
|
|
421
|
-
import { spawnSync } from "child_process";
|
|
421
|
+
import { spawn, spawnSync } from "child_process";
|
|
422
422
|
import { cpSync as cpSync2, existsSync as existsSync4, readdirSync as readdirSync3, readFileSync as readFileSync2, renameSync, writeFileSync as writeFileSync3 } from "fs";
|
|
423
423
|
import { basename, join as join6, resolve as resolve4 } from "path";
|
|
424
424
|
import { fileURLToPath } from "url";
|
|
425
425
|
import { defineCommand as defineCommand5 } from "citty";
|
|
426
|
+
|
|
427
|
+
// src/ui.ts
|
|
428
|
+
var TTY = Boolean(process.stdout.isTTY) && !process.env.NO_COLOR && process.env.TERM !== "dumb";
|
|
429
|
+
var RESET = "\x1B[0m";
|
|
430
|
+
function truecolor(r, g, b, s) {
|
|
431
|
+
return TTY ? `\x1B[38;2;${r};${g};${b}m${s}${RESET}` : s;
|
|
432
|
+
}
|
|
433
|
+
function style(code, s) {
|
|
434
|
+
return TTY ? `\x1B[${code}m${s}${RESET}` : s;
|
|
435
|
+
}
|
|
436
|
+
var color = {
|
|
437
|
+
cyan: (s) => truecolor(34, 211, 238, s),
|
|
438
|
+
indigo: (s) => truecolor(129, 140, 248, s),
|
|
439
|
+
green: (s) => truecolor(52, 211, 153, s),
|
|
440
|
+
red: (s) => truecolor(248, 113, 113, s),
|
|
441
|
+
gray: (s) => truecolor(154, 166, 196, s),
|
|
442
|
+
bold: (s) => style("1", s),
|
|
443
|
+
dim: (s) => style("2", s)
|
|
444
|
+
};
|
|
445
|
+
var LOGO = [
|
|
446
|
+
" \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557",
|
|
447
|
+
"\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u255A\u2588\u2588\u2557\u2588\u2588\u2554\u255D",
|
|
448
|
+
"\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2557 \u255A\u2588\u2588\u2588\u2554\u255D ",
|
|
449
|
+
"\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2588\u2588\u2557 ",
|
|
450
|
+
"\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2554\u255D \u2588\u2588\u2557",
|
|
451
|
+
"\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D"
|
|
452
|
+
];
|
|
453
|
+
var FROM = [99, 102, 241];
|
|
454
|
+
var TO = [34, 211, 238];
|
|
455
|
+
function banner(subtitle = "The full-stack, AI-native meta-framework for Alpine.js") {
|
|
456
|
+
const width = LOGO[0].length;
|
|
457
|
+
const rows = LOGO.map((line) => {
|
|
458
|
+
if (!TTY) return ` ${line}`;
|
|
459
|
+
let out = " ";
|
|
460
|
+
for (let i = 0; i < line.length; i++) {
|
|
461
|
+
const t = width > 1 ? i / (width - 1) : 0;
|
|
462
|
+
const r = Math.round(FROM[0] + (TO[0] - FROM[0]) * t);
|
|
463
|
+
const g = Math.round(FROM[1] + (TO[1] - FROM[1]) * t);
|
|
464
|
+
const b = Math.round(FROM[2] + (TO[2] - FROM[2]) * t);
|
|
465
|
+
out += `\x1B[38;2;${r};${g};${b}m${line[i]}`;
|
|
466
|
+
}
|
|
467
|
+
return out + RESET;
|
|
468
|
+
});
|
|
469
|
+
return `
|
|
470
|
+
${rows.join("\n")}
|
|
471
|
+
${color.gray(subtitle)}
|
|
472
|
+
`;
|
|
473
|
+
}
|
|
474
|
+
var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
475
|
+
function spinner(text) {
|
|
476
|
+
if (!TTY) {
|
|
477
|
+
process.stdout.write(` ${text}
|
|
478
|
+
`);
|
|
479
|
+
return {
|
|
480
|
+
succeed: (t) => console.log(` ${color.green("\u2713")} ${t || text}`),
|
|
481
|
+
fail: (t) => console.log(` ${color.red("\u2717")} ${t || text}`),
|
|
482
|
+
stop: () => {
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
let i = 0;
|
|
487
|
+
process.stdout.write("\x1B[?25l");
|
|
488
|
+
const id = setInterval(() => {
|
|
489
|
+
process.stdout.write(`\r\x1B[2K ${color.cyan(FRAMES[i++ % FRAMES.length])} ${text}`);
|
|
490
|
+
}, 80);
|
|
491
|
+
const end = (symbol, t) => {
|
|
492
|
+
clearInterval(id);
|
|
493
|
+
process.stdout.write(`\r\x1B[2K ${symbol} ${t || text}
|
|
494
|
+
\x1B[?25h`);
|
|
495
|
+
};
|
|
496
|
+
return {
|
|
497
|
+
succeed: (t) => end(color.green("\u2713"), t),
|
|
498
|
+
fail: (t) => end(color.red("\u2717"), t),
|
|
499
|
+
stop: () => {
|
|
500
|
+
clearInterval(id);
|
|
501
|
+
process.stdout.write("\r\x1B[2K\x1B[?25h");
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
function ready(rows) {
|
|
506
|
+
const w = Math.max(...rows.map(([l]) => l.length));
|
|
507
|
+
console.log();
|
|
508
|
+
for (const [label, value] of rows) {
|
|
509
|
+
console.log(` ${color.cyan("\u279C")} ${color.bold(label.padEnd(w))} ${color.cyan(value)}`);
|
|
510
|
+
}
|
|
511
|
+
console.log();
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// src/commands/new.ts
|
|
426
515
|
var TEMPLATE_DIR = fileURLToPath(new URL("../templates/default", import.meta.url));
|
|
427
516
|
function detectPackageManager() {
|
|
428
517
|
const ua = process.env.npm_config_user_agent || "";
|
|
@@ -431,21 +520,17 @@ function detectPackageManager() {
|
|
|
431
520
|
if (ua.startsWith("bun")) return "bun";
|
|
432
521
|
return "npm";
|
|
433
522
|
}
|
|
434
|
-
function
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
523
|
+
function runSync(cmd, args, cwd) {
|
|
524
|
+
return spawnSync(cmd, args, { cwd, stdio: "ignore", shell: process.platform === "win32" }).status === 0;
|
|
525
|
+
}
|
|
526
|
+
function installAsync(pm, cwd) {
|
|
527
|
+
const args = pm === "npm" ? ["install", "--no-audit", "--no-fund"] : ["install"];
|
|
528
|
+
return new Promise((res) => {
|
|
529
|
+
const child = spawn(pm, args, { cwd, stdio: "ignore", shell: process.platform === "win32" });
|
|
530
|
+
child.on("close", (code) => res(code === 0));
|
|
531
|
+
child.on("error", () => res(false));
|
|
440
532
|
});
|
|
441
|
-
return res.status === 0;
|
|
442
533
|
}
|
|
443
|
-
var c = {
|
|
444
|
-
cyan: (s) => `\x1B[36m${s}\x1B[0m`,
|
|
445
|
-
dim: (s) => `\x1B[2m${s}\x1B[0m`,
|
|
446
|
-
green: (s) => `\x1B[32m${s}\x1B[0m`,
|
|
447
|
-
yellow: (s) => `\x1B[33m${s}\x1B[0m`
|
|
448
|
-
};
|
|
449
534
|
var newCommand = defineCommand5({
|
|
450
535
|
meta: { name: "new", description: "Scaffold a new Apex JS app" },
|
|
451
536
|
args: {
|
|
@@ -453,12 +538,14 @@ var newCommand = defineCommand5({
|
|
|
453
538
|
install: { type: "boolean", default: true, description: "Install dependencies (use --no-install to skip)" },
|
|
454
539
|
git: { type: "boolean", default: true, description: "Initialize a git repository (use --no-git to skip)" }
|
|
455
540
|
},
|
|
456
|
-
run({ args }) {
|
|
457
|
-
const
|
|
541
|
+
async run({ args }) {
|
|
542
|
+
const dir = String(args.dir);
|
|
543
|
+
const target = resolve4(process.cwd(), dir);
|
|
458
544
|
const name = basename(target);
|
|
545
|
+
process.stdout.write(banner());
|
|
546
|
+
const log = console.log;
|
|
459
547
|
if (existsSync4(target) && readdirSync3(target).length > 0) {
|
|
460
|
-
console.error(`
|
|
461
|
-
\u2717 Target directory is not empty: ${target}
|
|
548
|
+
console.error(` ${color.red("\u2717")} Target directory is not empty: ${target}
|
|
462
549
|
`);
|
|
463
550
|
process.exit(1);
|
|
464
551
|
}
|
|
@@ -469,41 +556,34 @@ var newCommand = defineCommand5({
|
|
|
469
556
|
const file = join6(target, rel);
|
|
470
557
|
if (existsSync4(file)) writeFileSync3(file, readFileSync2(file, "utf8").replaceAll("{{name}}", name));
|
|
471
558
|
}
|
|
472
|
-
|
|
473
|
-
log(`
|
|
474
|
-
${c.cyan("Apex JS")} app created in ${args.dir}`);
|
|
559
|
+
log(` ${color.green("\u2713")} Created ${color.bold(dir)}`);
|
|
475
560
|
const pm = detectPackageManager();
|
|
476
561
|
let gitOk = false;
|
|
477
562
|
if (args.git) {
|
|
478
563
|
const hasGit = spawnSync("git", ["--version"], { stdio: "ignore", shell: process.platform === "win32" }).status === 0;
|
|
479
|
-
if (hasGit &&
|
|
480
|
-
|
|
481
|
-
|
|
564
|
+
if (hasGit && runSync("git", ["init", "-q"], target)) {
|
|
565
|
+
runSync("git", ["add", "-A"], target);
|
|
566
|
+
runSync("git", ["commit", "-m", "Initial commit from Apex JS", "--no-gpg-sign"], target);
|
|
482
567
|
gitOk = true;
|
|
483
568
|
}
|
|
484
569
|
}
|
|
570
|
+
if (gitOk) log(` ${color.green("\u2713")} Initialized a git repository`);
|
|
485
571
|
let installed = false;
|
|
486
572
|
if (args.install) {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
`);
|
|
490
|
-
|
|
491
|
-
installed = run(pm, installArgs, target);
|
|
492
|
-
if (!installed) log(`
|
|
493
|
-
${c.yellow("\u26A0")} Dependency install failed \u2014 run it yourself after cd'ing in.
|
|
494
|
-
`);
|
|
573
|
+
const sp = spinner(`Installing dependencies with ${pm}\u2026 ${color.dim("(first run can take a minute)")}`);
|
|
574
|
+
installed = await installAsync(pm, target);
|
|
575
|
+
if (installed) sp.succeed(`Dependencies installed with ${pm}`);
|
|
576
|
+
else sp.fail(`Install failed \u2014 run ${color.cyan(`${pm} install`)} inside ${dir}`);
|
|
495
577
|
}
|
|
496
578
|
const runPrefix = pm === "npm" ? "npm run" : pm;
|
|
497
|
-
const steps = [`cd ${args.dir}`];
|
|
498
|
-
if (!installed) steps.push(pm === "yarn" ? "yarn" : `${pm} install`);
|
|
499
|
-
steps.push(`apex dev ${c.dim("# start the dev server \u2192 http://localhost:3000")}`);
|
|
500
579
|
log(`
|
|
501
|
-
${
|
|
502
|
-
${
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
${
|
|
580
|
+
${color.bold("Next steps")}`);
|
|
581
|
+
log(` ${color.cyan(`cd ${dir}`)}`);
|
|
582
|
+
if (!installed) log(` ${color.cyan(pm === "yarn" ? "yarn" : `${pm} install`)}`);
|
|
583
|
+
log(` ${color.cyan("apex dev")} ${color.gray("# \u2192 http://localhost:3000")}`);
|
|
584
|
+
log(`
|
|
585
|
+
${color.gray("Not installed globally? Use")} ${color.cyan(`${runPrefix} dev`)}${color.gray(".")}`);
|
|
586
|
+
log(` ${color.gray("Islands mode:")} ${color.cyan("apex dev --islands")}${color.gray(" \xB7 API routes are also MCP tools at /mcp.")}
|
|
507
587
|
`);
|
|
508
588
|
}
|
|
509
589
|
});
|
|
@@ -637,13 +717,30 @@ var dev = defineCommand7({
|
|
|
637
717
|
async run({ args }) {
|
|
638
718
|
const root = resolve6(process.cwd(), args.root);
|
|
639
719
|
const port = Number(args.port);
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
720
|
+
process.stdout.write(banner());
|
|
721
|
+
const sp = spinner(`Starting dev server${args.islands ? " (islands mode)" : ""}\u2026`);
|
|
722
|
+
try {
|
|
723
|
+
const { port: actual } = await startDevServer({ root, port, islands: args.islands });
|
|
724
|
+
sp.succeed("Dev server ready");
|
|
725
|
+
ready([
|
|
726
|
+
["Local", `http://localhost:${actual}/`],
|
|
727
|
+
["MCP", `http://localhost:${actual}/mcp`]
|
|
728
|
+
]);
|
|
729
|
+
} catch (err) {
|
|
730
|
+
sp.fail("Failed to start the dev server");
|
|
731
|
+
throw err;
|
|
732
|
+
}
|
|
645
733
|
}
|
|
646
734
|
});
|
|
735
|
+
var COMMANDS = [
|
|
736
|
+
["new", "Scaffold a new app"],
|
|
737
|
+
["dev", "Start the dev server (SSR + hydrate, API + MCP)"],
|
|
738
|
+
["build", "Build for production (static, islands, or server)"],
|
|
739
|
+
["start", "Run a production server build"],
|
|
740
|
+
["make", "Generate a page, component, or API route"],
|
|
741
|
+
["migrate", "Apply pending database migrations"],
|
|
742
|
+
["mcp", "Inspect the MCP server \u2014 list or call tools"]
|
|
743
|
+
];
|
|
647
744
|
var main = defineCommand7({
|
|
648
745
|
meta: {
|
|
649
746
|
name: "apex",
|
|
@@ -657,6 +754,21 @@ var main = defineCommand7({
|
|
|
657
754
|
make: makeCommand,
|
|
658
755
|
migrate: migrateCommand,
|
|
659
756
|
mcp: mcpCommand
|
|
757
|
+
},
|
|
758
|
+
// Shown for a bare `apex` (no subcommand): the brand banner + a command menu.
|
|
759
|
+
run({ rawArgs }) {
|
|
760
|
+
if (rawArgs.length > 0) return;
|
|
761
|
+
process.stdout.write(banner());
|
|
762
|
+
const log = console.log;
|
|
763
|
+
log(` ${color.bold("Usage")} ${color.gray("apex")} ${color.cyan("<command>")} ${color.gray("[options]")}
|
|
764
|
+
`);
|
|
765
|
+
log(` ${color.bold("Commands")}`);
|
|
766
|
+
for (const [name, desc] of COMMANDS) {
|
|
767
|
+
log(` ${color.cyan(`apex ${name}`.padEnd(13))} ${color.gray(desc)}`);
|
|
768
|
+
}
|
|
769
|
+
log(`
|
|
770
|
+
${color.gray("Run")} ${color.cyan("apex <command> --help")} ${color.gray("for details.")}
|
|
771
|
+
`);
|
|
660
772
|
}
|
|
661
773
|
});
|
|
662
774
|
runMain(main);
|