alepha 0.14.0 → 0.14.2

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 (149) hide show
  1. package/README.md +3 -3
  2. package/dist/api/audits/index.d.ts +80 -1
  3. package/dist/api/audits/index.d.ts.map +1 -1
  4. package/dist/api/audits/index.js.map +1 -1
  5. package/dist/api/files/index.d.ts +80 -1
  6. package/dist/api/files/index.d.ts.map +1 -1
  7. package/dist/api/files/index.js.map +1 -1
  8. package/dist/api/jobs/index.d.ts +236 -157
  9. package/dist/api/jobs/index.d.ts.map +1 -1
  10. package/dist/api/jobs/index.js.map +1 -1
  11. package/dist/api/notifications/index.d.ts +21 -1
  12. package/dist/api/notifications/index.d.ts.map +1 -1
  13. package/dist/api/parameters/index.d.ts +451 -4
  14. package/dist/api/parameters/index.d.ts.map +1 -1
  15. package/dist/api/parameters/index.js.map +1 -1
  16. package/dist/api/users/index.d.ts +252 -249
  17. package/dist/api/users/index.d.ts.map +1 -1
  18. package/dist/api/users/index.js +4 -0
  19. package/dist/api/users/index.js.map +1 -1
  20. package/dist/api/verifications/index.d.ts +128 -128
  21. package/dist/api/verifications/index.d.ts.map +1 -1
  22. package/dist/batch/index.js.map +1 -1
  23. package/dist/cache/core/index.js.map +1 -1
  24. package/dist/cli/index.d.ts +304 -115
  25. package/dist/cli/index.d.ts.map +1 -1
  26. package/dist/cli/index.js +650 -531
  27. package/dist/cli/index.js.map +1 -1
  28. package/dist/command/index.d.ts +210 -13
  29. package/dist/command/index.d.ts.map +1 -1
  30. package/dist/command/index.js +306 -69
  31. package/dist/command/index.js.map +1 -1
  32. package/dist/core/index.browser.js.map +1 -1
  33. package/dist/core/index.d.ts +1 -1
  34. package/dist/core/index.d.ts.map +1 -1
  35. package/dist/core/index.js +7 -6
  36. package/dist/core/index.js.map +1 -1
  37. package/dist/core/index.native.js +7 -6
  38. package/dist/core/index.native.js.map +1 -1
  39. package/dist/datetime/index.js.map +1 -1
  40. package/dist/fake/index.js.map +1 -1
  41. package/dist/file/index.d.ts.map +1 -1
  42. package/dist/file/index.js.map +1 -1
  43. package/dist/lock/redis/index.js.map +1 -1
  44. package/dist/logger/index.js.map +1 -1
  45. package/dist/mcp/index.js.map +1 -1
  46. package/dist/orm/index.browser.js +26 -5
  47. package/dist/orm/index.browser.js.map +1 -1
  48. package/dist/orm/index.d.ts +294 -215
  49. package/dist/orm/index.d.ts.map +1 -1
  50. package/dist/orm/index.js +522 -523
  51. package/dist/orm/index.js.map +1 -1
  52. package/dist/queue/redis/index.js +2 -4
  53. package/dist/queue/redis/index.js.map +1 -1
  54. package/dist/redis/index.d.ts +400 -29
  55. package/dist/redis/index.d.ts.map +1 -1
  56. package/dist/redis/index.js +412 -21
  57. package/dist/redis/index.js.map +1 -1
  58. package/dist/retry/index.js.map +1 -1
  59. package/dist/router/index.js.map +1 -1
  60. package/dist/scheduler/index.js.map +1 -1
  61. package/dist/security/index.d.ts.map +1 -1
  62. package/dist/security/index.js.map +1 -1
  63. package/dist/server/auth/index.d.ts +155 -155
  64. package/dist/server/auth/index.js.map +1 -1
  65. package/dist/server/cache/index.js.map +1 -1
  66. package/dist/server/cookies/index.browser.js.map +1 -1
  67. package/dist/server/cookies/index.js.map +1 -1
  68. package/dist/server/core/index.browser.js.map +1 -1
  69. package/dist/server/core/index.d.ts +0 -1
  70. package/dist/server/core/index.d.ts.map +1 -1
  71. package/dist/server/core/index.js.map +1 -1
  72. package/dist/server/helmet/index.d.ts +4 -1
  73. package/dist/server/helmet/index.d.ts.map +1 -1
  74. package/dist/server/helmet/index.js.map +1 -1
  75. package/dist/server/links/index.browser.js.map +1 -1
  76. package/dist/server/links/index.js.map +1 -1
  77. package/dist/server/multipart/index.d.ts.map +1 -1
  78. package/dist/server/multipart/index.js.map +1 -1
  79. package/dist/server/proxy/index.js.map +1 -1
  80. package/dist/server/rate-limit/index.js.map +1 -1
  81. package/dist/server/security/index.d.ts +9 -9
  82. package/dist/server/security/index.js.map +1 -1
  83. package/dist/server/swagger/index.js.map +1 -1
  84. package/dist/thread/index.js.map +1 -1
  85. package/dist/topic/core/index.js.map +1 -1
  86. package/dist/topic/redis/index.js +3 -3
  87. package/dist/topic/redis/index.js.map +1 -1
  88. package/dist/vite/index.js +9 -6
  89. package/dist/vite/index.js.map +1 -1
  90. package/dist/websocket/index.browser.js.map +1 -1
  91. package/dist/websocket/index.d.ts +7 -7
  92. package/dist/websocket/index.js.map +1 -1
  93. package/package.json +3 -3
  94. package/src/api/users/index.ts +4 -0
  95. package/src/cli/apps/AlephaCli.ts +36 -14
  96. package/src/cli/apps/AlephaPackageBuilderCli.ts +5 -1
  97. package/src/cli/assets/appRouterTs.ts +1 -1
  98. package/src/cli/atoms/changelogOptions.ts +45 -0
  99. package/src/cli/commands/{ViteCommands.ts → build.ts} +4 -93
  100. package/src/cli/commands/changelog.ts +244 -0
  101. package/src/cli/commands/clean.ts +14 -0
  102. package/src/cli/commands/{DrizzleCommands.ts → db.ts} +37 -124
  103. package/src/cli/commands/deploy.ts +118 -0
  104. package/src/cli/commands/dev.ts +57 -0
  105. package/src/cli/commands/format.ts +17 -0
  106. package/src/cli/commands/{CoreCommands.ts → init.ts} +2 -40
  107. package/src/cli/commands/lint.ts +17 -0
  108. package/src/cli/commands/root.ts +32 -0
  109. package/src/cli/commands/run.ts +24 -0
  110. package/src/cli/commands/test.ts +42 -0
  111. package/src/cli/commands/typecheck.ts +19 -0
  112. package/src/cli/commands/{VerifyCommands.ts → verify.ts} +1 -13
  113. package/src/cli/defineConfig.ts +24 -0
  114. package/src/cli/index.ts +17 -5
  115. package/src/cli/services/AlephaCliUtils.ts +4 -21
  116. package/src/cli/services/GitMessageParser.ts +77 -0
  117. package/src/command/helpers/EnvUtils.ts +37 -0
  118. package/src/command/index.ts +3 -1
  119. package/src/command/primitives/$command.ts +172 -6
  120. package/src/command/providers/CliProvider.ts +424 -91
  121. package/src/core/Alepha.ts +8 -5
  122. package/src/file/providers/NodeFileSystemProvider.ts +3 -1
  123. package/src/orm/index.browser.ts +1 -1
  124. package/src/orm/index.ts +18 -10
  125. package/src/orm/interfaces/PgQueryWhere.ts +1 -26
  126. package/src/orm/providers/{PostgresTypeProvider.ts → DatabaseTypeProvider.ts} +25 -3
  127. package/src/orm/providers/drivers/BunPostgresProvider.ts +225 -0
  128. package/src/orm/providers/drivers/BunSqliteProvider.ts +180 -0
  129. package/src/orm/providers/drivers/DatabaseProvider.ts +25 -0
  130. package/src/orm/providers/drivers/NodePostgresProvider.ts +0 -25
  131. package/src/orm/services/QueryManager.ts +10 -125
  132. package/src/queue/redis/providers/RedisQueueProvider.ts +2 -7
  133. package/src/redis/index.ts +65 -3
  134. package/src/redis/providers/BunRedisProvider.ts +304 -0
  135. package/src/redis/providers/BunRedisSubscriberProvider.ts +94 -0
  136. package/src/redis/providers/NodeRedisProvider.ts +280 -0
  137. package/src/redis/providers/NodeRedisSubscriberProvider.ts +94 -0
  138. package/src/redis/providers/RedisProvider.ts +134 -140
  139. package/src/redis/providers/RedisSubscriberProvider.ts +58 -49
  140. package/src/server/core/providers/BunHttpServerProvider.ts +0 -3
  141. package/src/server/core/providers/ServerBodyParserProvider.ts +3 -1
  142. package/src/server/core/providers/ServerProvider.ts +7 -4
  143. package/src/server/multipart/providers/ServerMultipartProvider.ts +3 -1
  144. package/src/server/proxy/providers/ServerProxyProvider.ts +1 -1
  145. package/src/topic/redis/providers/RedisTopicProvider.ts +3 -3
  146. package/src/vite/tasks/buildServer.ts +1 -0
  147. package/src/cli/commands/BiomeCommands.ts +0 -29
  148. package/src/cli/commands/ChangelogCommands.ts +0 -389
  149. package/src/orm/services/PgJsonQueryManager.ts +0 -511
@@ -2,10 +2,11 @@ import { $atom, $env, $hook, $inject, $module, $use, Alepha, AlephaError, KIND,
2
2
  import { stdin, stdout } from "node:process";
3
3
  import { createInterface } from "node:readline/promises";
4
4
  import { $logger } from "alepha/logger";
5
+ import * as fs from "node:fs/promises";
6
+ import { cp, glob, readFile, rm } from "node:fs/promises";
7
+ import { join } from "node:path";
5
8
  import { DateTimeProvider } from "alepha/datetime";
6
9
  import { exec } from "node:child_process";
7
- import * as fs from "node:fs/promises";
8
- import { cp, glob, rm } from "node:fs/promises";
9
10
 
10
11
  //#region ../../src/command/helpers/Asker.ts
11
12
  var Asker = class {
@@ -60,6 +61,35 @@ var Asker = class {
60
61
  }
61
62
  };
62
63
 
64
+ //#endregion
65
+ //#region ../../src/command/helpers/EnvUtils.ts
66
+ var EnvUtils = class {
67
+ log = $logger();
68
+ /**
69
+ * Load environment variables from .env files into process.env.
70
+ * By default, it loads from ".env" and ".env.local".
71
+ * You can specify additional files to load, e.g. [".env", ".env.production"].
72
+ */
73
+ async loadEnv(root, files = [".env"]) {
74
+ for (const it of files) for (const file of [it, `${it}.local`]) {
75
+ const envPath = join(root, file);
76
+ try {
77
+ const lines = (await readFile(envPath, "utf8")).split("\n");
78
+ for (const line of lines) {
79
+ const [key, ...rest] = line.split("=");
80
+ if (key) {
81
+ const value = rest.join("=");
82
+ process.env[key.trim()] = value.trim();
83
+ }
84
+ }
85
+ this.log.debug(`Loaded environment variables from ${envPath}`);
86
+ } catch {
87
+ this.log.debug(`No ${file} file found at ${envPath}, skipping load.`);
88
+ }
89
+ }
90
+ }
91
+ };
92
+
63
93
  //#endregion
64
94
  //#region ../../src/command/helpers/PrettyPrint.ts
65
95
  var PrettyPrint = class {
@@ -358,6 +388,7 @@ var Runner = class {
358
388
  const $command = (options) => createPrimitive(CommandPrimitive, options);
359
389
  var CommandPrimitive = class extends Primitive {
360
390
  flags = this.options.flags ?? t.object({});
391
+ env = this.options.env ?? t.object({});
361
392
  aliases = this.options.aliases ?? [];
362
393
  onInit() {
363
394
  if (this.options.pre || this.options.post) this.options.hide ??= true;
@@ -368,6 +399,24 @@ var CommandPrimitive = class extends Primitive {
368
399
  if (this.options.post) return `post${this.options.post}`;
369
400
  return this.options.name ?? `${this.config.propertyKey}`;
370
401
  }
402
+ /**
403
+ * Get the child commands (subcommands) for this command.
404
+ */
405
+ get children() {
406
+ return this.options.children ?? [];
407
+ }
408
+ /**
409
+ * Check if this command has child commands (is a parent command).
410
+ */
411
+ get hasChildren() {
412
+ return this.children.length > 0;
413
+ }
414
+ /**
415
+ * Find a child command by name or alias.
416
+ */
417
+ findChild(name) {
418
+ return this.children.find((child) => child.name === name || child.aliases.includes(name));
419
+ }
371
420
  };
372
421
  $command[KIND] = CommandPrimitive;
373
422
 
@@ -401,6 +450,7 @@ var CliProvider = class {
401
450
  log = $logger();
402
451
  runner = $inject(Runner);
403
452
  asker = $inject(Asker);
453
+ envUtils = $inject(EnvUtils);
404
454
  options = $use(cliOptions);
405
455
  get name() {
406
456
  return this.options.name || this.env.CLI_NAME;
@@ -420,8 +470,8 @@ var CliProvider = class {
420
470
  on: "ready",
421
471
  handler: async () => {
422
472
  const argv = [...this.argv];
423
- const commandName = argv.find((arg) => !arg.startsWith("-")) ?? "";
424
- let command = this.findCommand(commandName);
473
+ const positionalArgs = argv.filter((arg) => !arg.startsWith("-"));
474
+ const { command, consumedArgs } = this.resolveCommand(positionalArgs);
425
475
  if (this.parseFlags(argv, Object.entries(this.getAllGlobalFlags()).map(([key, value]) => ({
426
476
  key,
427
477
  ...value
@@ -431,49 +481,124 @@ var CliProvider = class {
431
481
  }
432
482
  if (!command) {
433
483
  const rootCommand = this.findCommand("");
434
- if (rootCommand?.options.args) command = rootCommand;
435
- else {
436
- if (commandName !== "") {
437
- this.log.error(`Unknown command: '${commandName}'`);
438
- this.printHelp();
439
- }
484
+ const commandName = positionalArgs[0] ?? "";
485
+ if (commandName !== "" && !rootCommand?.options.args) {
486
+ this.log.error(`Unknown command: '${commandName}'`);
487
+ this.printHelp();
440
488
  return;
441
489
  }
442
- }
443
- const commandFlags = this.parseCommandFlags(argv, command.flags);
444
- const commandArgs = this.parseCommandArgs(argv, command.options.args, command.name === "", command.flags);
445
- await this.alepha.context.run(async () => {
446
- this.log.debug(`Executing command '${command.name}'...`, {
447
- flags: commandFlags,
448
- args: commandArgs
449
- });
450
- const runner = this.runner;
451
- runner.startCommand(this.name, command.name);
452
- const args = {
453
- flags: commandFlags,
454
- args: commandArgs,
455
- run: runner.run,
456
- ask: this.asker.ask,
457
- fs,
458
- glob,
459
- root: process.cwd()
460
- };
461
- const preHooks = this.findPreHooks(command.name);
462
- for (const hook of preHooks) {
463
- this.log.debug(`Executing pre-hook for '${command.name}'...`);
464
- await hook.options.handler(args);
465
- }
466
- await command.options.handler(args);
467
- const postHooks = this.findPostHooks(command.name);
468
- for (const hook of postHooks) {
469
- this.log.debug(`Executing post-hook for '${command.name}'...`);
470
- await hook.options.handler(args);
490
+ if (rootCommand) {
491
+ await this.executeCommand(rootCommand, argv, true);
492
+ return;
471
493
  }
472
- if (command.options.summary !== false) runner.summary();
473
- this.log.debug(`Command '${command.name}' executed successfully.`);
474
- });
494
+ return;
495
+ }
496
+ const remainingArgv = this.removeConsumedArgs(argv, consumedArgs);
497
+ await this.executeCommand(command, remainingArgv, true);
475
498
  }
476
499
  });
500
+ /**
501
+ * Execute a command with the given argv.
502
+ */
503
+ async executeCommand(command, argv, isRootCommand) {
504
+ const root = process.cwd();
505
+ let modeValue;
506
+ if (command.options.mode) {
507
+ modeValue = this.parseModeFlag(argv);
508
+ if (modeValue === void 0 && typeof command.options.mode === "string") modeValue = command.options.mode;
509
+ await this.loadModeEnv(root, modeValue);
510
+ }
511
+ const commandFlags = this.parseCommandFlags(argv, command.flags);
512
+ const commandArgs = this.parseCommandArgs(argv, command.options.args, isRootCommand, command.flags);
513
+ const commandEnv = this.parseCommandEnv(command.env, command.name);
514
+ await this.alepha.context.run(async () => {
515
+ this.log.debug(`Executing command '${command.name}'...`, {
516
+ flags: commandFlags,
517
+ args: commandArgs,
518
+ mode: modeValue
519
+ });
520
+ const runner = this.runner;
521
+ runner.startCommand(this.name, command.name);
522
+ const args = {
523
+ flags: commandFlags,
524
+ args: commandArgs,
525
+ env: commandEnv,
526
+ run: runner.run,
527
+ ask: this.asker.ask,
528
+ fs,
529
+ glob,
530
+ root,
531
+ help: () => this.printHelp(command),
532
+ mode: modeValue
533
+ };
534
+ const preHooks = this.findPreHooks(command.name);
535
+ for (const hook of preHooks) {
536
+ this.log.debug(`Executing pre-hook for '${command.name}'...`);
537
+ await hook.options.handler(args);
538
+ }
539
+ await command.options.handler(args);
540
+ const postHooks = this.findPostHooks(command.name);
541
+ for (const hook of postHooks) {
542
+ this.log.debug(`Executing post-hook for '${command.name}'...`);
543
+ await hook.options.handler(args);
544
+ }
545
+ if (command.options.summary !== false) runner.summary();
546
+ this.log.debug(`Command '${command.name}' executed successfully.`);
547
+ });
548
+ }
549
+ /**
550
+ * Remove consumed command path arguments from argv.
551
+ */
552
+ removeConsumedArgs(argv, consumedArgs) {
553
+ const result = [];
554
+ let consumedIndex = 0;
555
+ for (const arg of argv) if (arg.startsWith("-")) result.push(arg);
556
+ else if (consumedIndex < consumedArgs.length && arg === consumedArgs[consumedIndex]) consumedIndex++;
557
+ else result.push(arg);
558
+ return result;
559
+ }
560
+ /**
561
+ * Resolve a command from positional arguments.
562
+ *
563
+ * Supports:
564
+ * 1. Space-separated subcommands: `deploy vercel` -> finds deploy command, then vercel child
565
+ * 2. Colon notation (backwards compat): `deploy:vercel` -> finds command with name "deploy:vercel"
566
+ * 3. Simple commands: `build` -> finds command with name "build"
567
+ */
568
+ resolveCommand(positionalArgs) {
569
+ if (positionalArgs.length === 0) return {
570
+ command: void 0,
571
+ consumedArgs: []
572
+ };
573
+ const firstArg = positionalArgs[0];
574
+ if (firstArg.includes(":")) {
575
+ const command = this.findCommand(firstArg);
576
+ if (command) return {
577
+ command,
578
+ consumedArgs: [firstArg]
579
+ };
580
+ }
581
+ let currentCommand = this.findCommand(firstArg);
582
+ const consumedArgs = [];
583
+ if (!currentCommand) return {
584
+ command: void 0,
585
+ consumedArgs: []
586
+ };
587
+ consumedArgs.push(firstArg);
588
+ for (let i = 1; i < positionalArgs.length; i++) {
589
+ const arg = positionalArgs[i];
590
+ if (!currentCommand.hasChildren) break;
591
+ const childCommand = currentCommand.findChild(arg);
592
+ if (childCommand) {
593
+ currentCommand = childCommand;
594
+ consumedArgs.push(arg);
595
+ } else break;
596
+ }
597
+ return {
598
+ command: currentCommand,
599
+ consumedArgs
600
+ };
601
+ }
477
602
  get commands() {
478
603
  return this.alepha.primitives($command);
479
604
  }
@@ -493,17 +618,10 @@ var CliProvider = class {
493
618
  return this.commands.filter((cmd) => cmd.name === `post${commandName}`);
494
619
  }
495
620
  /**
496
- * Get all global flags including those from the root command (name === "")
621
+ * Get global flags (help only, root command flags are NOT global).
497
622
  */
498
623
  getAllGlobalFlags() {
499
- const rootCommand = this.commands.find((cmd) => cmd.name === "");
500
- const allGlobalFlags = { ...this.globalFlags };
501
- if (rootCommand) for (const [key, value] of Object.entries(rootCommand.flags.properties)) allGlobalFlags[key] = {
502
- aliases: [key, ...value.aliases ?? (value.alias ? [value.alias] : void 0) ?? []],
503
- description: value.description,
504
- schema: value
505
- };
506
- return allGlobalFlags;
624
+ return { ...this.globalFlags };
507
625
  }
508
626
  parseCommandFlags(argv, schema) {
509
627
  const flagDefs = Object.entries(schema.properties).map(([key, value]) => ({
@@ -524,6 +642,50 @@ var CliProvider = class {
524
642
  throw error;
525
643
  }
526
644
  }
645
+ parseCommandEnv(schema, commandName) {
646
+ const result = {};
647
+ const missing = [];
648
+ for (const [key, propSchema] of Object.entries(schema.properties)) {
649
+ const value = process.env[key];
650
+ if (value !== void 0) result[key] = value;
651
+ else if (t.schema.isOptional(propSchema)) {
652
+ if ("default" in propSchema) result[key] = propSchema.default;
653
+ } else missing.push(key);
654
+ }
655
+ if (missing.length > 0) {
656
+ const vars = missing.join(", ");
657
+ throw new CommandError(`Missing required environment variable${missing.length > 1 ? "s" : ""}: ${vars}`);
658
+ }
659
+ try {
660
+ return this.alepha.codec.decode(schema, result);
661
+ } catch (error) {
662
+ if (error instanceof TypeBoxError) throw new CommandError(`Invalid environment variable: ${error.cause.instancePath || "env"} ${error.cause.message}`);
663
+ throw error;
664
+ }
665
+ }
666
+ /**
667
+ * Parse --mode or -m flag from argv.
668
+ */
669
+ parseModeFlag(argv) {
670
+ for (let i = 0; i < argv.length; i++) {
671
+ const arg = argv[i];
672
+ if (arg.startsWith("--mode=") || arg.startsWith("-m=")) return arg.split("=")[1];
673
+ if (arg === "--mode" || arg === "-m") {
674
+ const nextArg = argv[i + 1];
675
+ if (nextArg && !nextArg.startsWith("-")) return nextArg;
676
+ throw new CommandError("Flag --mode requires a value.");
677
+ }
678
+ }
679
+ }
680
+ /**
681
+ * Load environment files based on mode.
682
+ */
683
+ async loadModeEnv(root, mode) {
684
+ const envFiles = [".env"];
685
+ if (mode) envFiles.push(`.env.${mode}`);
686
+ this.log.debug(`Loading env files: ${envFiles.join(", ")}`);
687
+ await this.envUtils.loadEnv(root, envFiles);
688
+ }
527
689
  parseFlags(argv, flagDefs) {
528
690
  const result = {};
529
691
  for (let i = 0; i < argv.length; i++) {
@@ -651,42 +813,80 @@ var CliProvider = class {
651
813
  const cliName = this.name || "cli";
652
814
  this.log.info("");
653
815
  if (command?.name) {
654
- const argsUsage = this.generateArgsUsage(command.options.args);
655
- const usage = `${cliName} ${command.name}${argsUsage}`.trim();
816
+ const hasChildren = command.hasChildren;
817
+ const argsUsage = hasChildren ? " <command>" : this.generateArgsUsage(command.options.args);
818
+ const usage = `${cliName} ${this.getCommandPath(command)}${argsUsage}`.trim();
656
819
  this.log.info(`Usage: \`${usage}\``);
657
820
  if (command.options.description) {
658
821
  this.log.info(``);
659
822
  this.log.info(`\t${command.options.description}`);
660
823
  }
824
+ if (hasChildren) {
825
+ this.log.info("");
826
+ this.log.info("Commands:");
827
+ const maxSubCmdLength = this.getMaxChildCmdLength(command.children);
828
+ for (const child of command.children) {
829
+ if (child.options.hide) continue;
830
+ const childArgsUsage = this.generateArgsUsage(child.options.args);
831
+ const fullCmdStr = `${[child.name, ...child.aliases].join(", ")}${childArgsUsage}`;
832
+ this.log.info(` ${cliName} ${command.name} ${fullCmdStr.padEnd(maxSubCmdLength)} # ${child.options.description ?? ""}`);
833
+ }
834
+ }
661
835
  this.log.info("");
662
836
  this.log.info("Flags:");
663
- const flags = [...Object.entries(command.flags.properties).map(([key, value]) => ({
664
- key,
665
- schema: value,
666
- aliases: value.alias ?? [key],
667
- description: value.description
668
- })), ...Object.entries(this.getAllGlobalFlags()).map(([key, value]) => ({
669
- key,
670
- ...value
671
- }))];
837
+ const flags = [
838
+ ...Object.entries(command.flags.properties).map(([key, value]) => ({
839
+ key,
840
+ schema: value,
841
+ aliases: value.alias ?? [key],
842
+ description: value.description
843
+ })),
844
+ ...command.options.mode ? [{
845
+ key: "mode",
846
+ aliases: ["m", "mode"],
847
+ description: typeof command.options.mode === "string" ? `Environment mode - loads .env.{mode} (default: ${command.options.mode})` : "Environment mode (e.g., production, staging) - loads .env.{mode}"
848
+ }] : [],
849
+ ...Object.entries(this.getAllGlobalFlags()).map(([key, value]) => ({
850
+ key,
851
+ ...value
852
+ }))
853
+ ];
672
854
  const maxFlagLength = this.getMaxFlagLength(flags);
673
855
  for (const { aliases, description } of flags) {
674
856
  const flagStr = (Array.isArray(aliases) ? aliases : [aliases]).map((a) => a.length === 1 ? `-${a}` : `--${a}`).join(", ");
675
857
  this.log.info(` ${flagStr.padEnd(maxFlagLength)} # ${description ?? ""}`);
676
858
  }
859
+ const envVars = Object.entries(command.env.properties);
860
+ if (envVars.length > 0) {
861
+ this.log.info("");
862
+ this.log.info("Env:");
863
+ const maxEnvLength = Math.max(...envVars.map(([key]) => key.length));
864
+ for (const [key, schema] of envVars) {
865
+ const isOptional = t.schema.isOptional(schema);
866
+ const description = schema.description ?? "";
867
+ const optionalStr = isOptional ? " (optional)" : "";
868
+ this.log.info(` ${key.padEnd(maxEnvLength)} # ${description}${optionalStr}`);
869
+ }
870
+ }
677
871
  } else {
678
872
  this.log.info(this.description || "Available commands:");
679
873
  this.log.info("");
680
874
  this.log.info("Commands:");
681
- const maxCmdLength = this.getMaxCmdLength(this.commands);
682
- for (const command$1 of this.commands) {
875
+ const topLevelCommands = this.getTopLevelCommands();
876
+ const maxCmdLength = this.getMaxCmdLength(topLevelCommands);
877
+ for (const command$1 of topLevelCommands) {
683
878
  if (command$1.name === "" || command$1.options.hide) continue;
684
- const fullCmdStr = `${[command$1.name, ...command$1.aliases].join(", ")}${this.generateArgsUsage(command$1.options.args)}`;
879
+ const fullCmdStr = `${[command$1.name, ...command$1.aliases].join(", ")}${command$1.hasChildren ? " <command>" : this.generateArgsUsage(command$1.options.args)}`;
685
880
  this.log.info(` ${cliName} ${fullCmdStr.padEnd(maxCmdLength)} # ${command$1.options.description ?? ""}`);
686
881
  }
687
882
  this.log.info("");
688
883
  this.log.info("Flags:");
689
- const globalFlags = Object.values(this.getAllGlobalFlags());
884
+ const rootCommand = this.commands.find((cmd) => cmd.name === "");
885
+ const globalFlags = [...rootCommand ? Object.entries(rootCommand.flags.properties).map(([key, value]) => ({
886
+ key,
887
+ aliases: [key, ...value.aliases ?? (value.alias ? [value.alias] : void 0) ?? []],
888
+ description: value.description
889
+ })) : [], ...Object.values(this.getAllGlobalFlags())];
690
890
  const maxFlagLength = this.getMaxFlagLength(globalFlags);
691
891
  for (const { aliases, description } of globalFlags) {
692
892
  const flagStr = aliases.map((a) => a.length === 1 ? `-${a}` : `--${a}`).join(", ");
@@ -695,9 +895,45 @@ var CliProvider = class {
695
895
  }
696
896
  this.log.info("");
697
897
  }
898
+ /**
899
+ * Get the full command path (e.g., "deploy vercel" for a child command).
900
+ */
901
+ getCommandPath(command) {
902
+ const path = [command.name];
903
+ let current = command;
904
+ while (true) {
905
+ const parent = this.findParentCommand(current);
906
+ if (!parent) break;
907
+ path.unshift(parent.name);
908
+ current = parent;
909
+ }
910
+ return path.join(" ");
911
+ }
912
+ /**
913
+ * Find the parent command of a given command.
914
+ */
915
+ findParentCommand(command) {
916
+ for (const cmd of this.commands) if (cmd.children.includes(command)) return cmd;
917
+ }
918
+ /**
919
+ * Get top-level commands (commands that are not children of other commands).
920
+ */
921
+ getTopLevelCommands() {
922
+ const allChildren = /* @__PURE__ */ new Set();
923
+ for (const command of this.commands) for (const child of command.children) allChildren.add(child);
924
+ return this.commands.filter((cmd) => !allChildren.has(cmd));
925
+ }
926
+ /**
927
+ * Get max length for child command display.
928
+ */
929
+ getMaxChildCmdLength(children) {
930
+ return Math.max(...children.filter((c) => !c.options.hide).map((c) => {
931
+ return `${[c.name, ...c.aliases].join(", ")}${this.generateArgsUsage(c.options.args)}`.length;
932
+ }), 0);
933
+ }
698
934
  getMaxCmdLength(commands) {
699
935
  return Math.max(...commands.filter((c) => !c.options.hide && c.name !== "").map((c) => {
700
- return `${[c.name, ...c.aliases].join(", ")}${this.generateArgsUsage(c.options.args)}`.length;
936
+ return `${[c.name, ...c.aliases].join(", ")}${c.hasChildren ? " <command>" : this.generateArgsUsage(c.options.args)}`.length;
701
937
  }));
702
938
  }
703
939
  getMaxFlagLength(flags) {
@@ -725,10 +961,11 @@ const AlephaCommand = $module({
725
961
  CliProvider,
726
962
  Runner,
727
963
  Asker,
728
- PrettyPrint
964
+ PrettyPrint,
965
+ EnvUtils
729
966
  ]
730
967
  });
731
968
 
732
969
  //#endregion
733
- export { $command, AlephaCommand, Asker, CliProvider, CommandError, CommandPrimitive, PrettyPrint, Runner, cliOptions };
970
+ export { $command, AlephaCommand, Asker, CliProvider, CommandError, CommandPrimitive, EnvUtils, PrettyPrint, Runner, cliOptions };
734
971
  //# sourceMappingURL=index.js.map