@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.
Files changed (2) hide show
  1. package/dist/cli.js +158 -46
  2. 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 run(cmd, cmdArgs, cwd, quiet = false) {
435
- const res = spawnSync(cmd, cmdArgs, {
436
- cwd,
437
- stdio: quiet ? "ignore" : "inherit",
438
- shell: process.platform === "win32"
439
- // npm/pnpm/yarn are .cmd shims on Windows
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 target = resolve4(process.cwd(), String(args.dir));
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
- const log = console.log;
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 && run("git", ["init", "-q"], target, true)) {
480
- run("git", ["add", "-A"], target, true);
481
- run("git", ["commit", "-m", "Initial commit from Apex JS", "--no-gpg-sign"], target, true);
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
- log(`
488
- Installing dependencies with ${c.cyan(pm)}\u2026 ${c.dim("(first install can take a minute)")}
489
- `);
490
- const installArgs = pm === "npm" ? ["install", "--no-audit", "--no-fund"] : ["install"];
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
- ${installed ? c.green("Ready.") : "Next steps:"}
502
- ${steps.map((s) => ` ${s}`).join("\n")}
503
-
504
- ${c.dim("Not global? Run")} ${c.cyan(runPrefix + " dev")}${c.dim(" instead of ")}${c.cyan("apex dev")}${c.dim(".")}
505
- ${c.dim("Islands mode:")} apex dev --islands
506
- ${gitOk ? c.dim("Git repository initialized. ") : ""}Your server/api/*.ts routes are also MCP tools at /mcp.
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
- const { port: actual } = await startDevServer({ root, port, islands: args.islands });
641
- console.log(`
642
- \x1B[36mApex JS\x1B[0m dev server ready
643
- \u2192 http://localhost:${actual}
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apex-stack/core",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "The full-stack meta-framework for Alpine.js — CLI and runtime",
5
5
  "type": "module",
6
6
  "license": "MIT",