@geekmidas/cli 0.37.0 → 0.39.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/index.cjs CHANGED
@@ -27,7 +27,7 @@ const node_module = require_chunk.__toESM(require("node:module"));
27
27
 
28
28
  //#region package.json
29
29
  var name = "@geekmidas/cli";
30
- var version = "0.37.0";
30
+ var version = "0.38.0";
31
31
  var description = "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs";
32
32
  var private$1 = false;
33
33
  var type = "module";
@@ -240,7 +240,7 @@ async function prompt$1(message, hidden = false) {
240
240
  if (!process.stdin.isTTY) throw new Error("Interactive input required. Please provide --token option.");
241
241
  if (hidden) {
242
242
  process.stdout.write(message);
243
- return new Promise((resolve$1, reject) => {
243
+ return new Promise((resolve$2, reject) => {
244
244
  let value = "";
245
245
  const cleanup = () => {
246
246
  process.stdin.setRawMode(false);
@@ -257,7 +257,7 @@ async function prompt$1(message, hidden = false) {
257
257
  if (c === "\n" || c === "\r") {
258
258
  cleanup();
259
259
  process.stdout.write("\n");
260
- resolve$1(value);
260
+ resolve$2(value);
261
261
  } else if (c === "") {
262
262
  cleanup();
263
263
  process.stdout.write("\n");
@@ -892,15 +892,15 @@ function loadEnvFiles(envConfig, cwd = process.cwd()) {
892
892
  * @internal Exported for testing
893
893
  */
894
894
  async function isPortAvailable(port) {
895
- return new Promise((resolve$1) => {
895
+ return new Promise((resolve$2) => {
896
896
  const server = (0, node_net.createServer)();
897
897
  server.once("error", (err) => {
898
- if (err.code === "EADDRINUSE") resolve$1(false);
899
- else resolve$1(false);
898
+ if (err.code === "EADDRINUSE") resolve$2(false);
899
+ else resolve$2(false);
900
900
  });
901
901
  server.once("listening", () => {
902
902
  server.close();
903
- resolve$1(true);
903
+ resolve$2(true);
904
904
  });
905
905
  server.listen(port);
906
906
  });
@@ -1491,7 +1491,7 @@ async function workspaceDevCommand(workspace, options) {
1491
1491
  };
1492
1492
  process.on("SIGINT", shutdown);
1493
1493
  process.on("SIGTERM", shutdown);
1494
- return new Promise((resolve$1, reject) => {
1494
+ return new Promise((resolve$2, reject) => {
1495
1495
  turboProcess.on("error", (error) => {
1496
1496
  logger$8.error("❌ Turbo error:", error);
1497
1497
  reject(error);
@@ -1499,7 +1499,7 @@ async function workspaceDevCommand(workspace, options) {
1499
1499
  turboProcess.on("exit", (code) => {
1500
1500
  if (endpointWatcher) endpointWatcher.close().catch(() => {});
1501
1501
  if (code !== null && code !== 0) reject(new Error(`Turbo exited with code ${code}`));
1502
- else resolve$1();
1502
+ else resolve$2();
1503
1503
  });
1504
1504
  });
1505
1505
  }
@@ -1542,19 +1542,43 @@ function findSecretsRoot(startDir) {
1542
1542
  return startDir;
1543
1543
  }
1544
1544
  /**
1545
- * Create a wrapper script that injects secrets before importing the entry file.
1546
- * @internal Exported for testing
1545
+ * Generate the credentials injection code snippet.
1546
+ * This is the common logic used by both entry wrapper and exec preload.
1547
+ * @internal
1547
1548
  */
1548
- async function createEntryWrapper(wrapperPath, entryPath, secretsJsonPath) {
1549
- const credentialsInjection = secretsJsonPath ? `import { Credentials } from '@geekmidas/envkit/credentials';
1549
+ function generateCredentialsInjection(secretsJsonPath) {
1550
+ return `import { Credentials } from '@geekmidas/envkit/credentials';
1550
1551
  import { existsSync, readFileSync } from 'node:fs';
1551
1552
 
1552
- // Inject dev secrets into Credentials (before app import)
1553
+ // Inject dev secrets into Credentials
1553
1554
  const secretsPath = '${secretsJsonPath}';
1554
1555
  if (existsSync(secretsPath)) {
1555
- Object.assign(Credentials, JSON.parse(readFileSync(secretsPath, 'utf-8')));
1556
+ const secrets = JSON.parse(readFileSync(secretsPath, 'utf-8'));
1557
+ Object.assign(Credentials, secrets);
1558
+ // Debug: uncomment to verify preload is running
1559
+ // console.log('[gkm preload] Injected', Object.keys(secrets).length, 'credentials');
1556
1560
  }
1557
-
1561
+ `;
1562
+ }
1563
+ /**
1564
+ * Create a preload script that injects secrets into Credentials.
1565
+ * Used by `gkm exec` to inject secrets before running any command.
1566
+ * @internal Exported for testing
1567
+ */
1568
+ async function createCredentialsPreload(preloadPath, secretsJsonPath) {
1569
+ const content = `/**
1570
+ * Credentials preload generated by 'gkm exec'
1571
+ * This file is loaded via NODE_OPTIONS="--import <path>"
1572
+ */
1573
+ ${generateCredentialsInjection(secretsJsonPath)}`;
1574
+ await (0, node_fs_promises.writeFile)(preloadPath, content);
1575
+ }
1576
+ /**
1577
+ * Create a wrapper script that injects secrets before importing the entry file.
1578
+ * @internal Exported for testing
1579
+ */
1580
+ async function createEntryWrapper(wrapperPath, entryPath, secretsJsonPath) {
1581
+ const credentialsInjection = secretsJsonPath ? `${generateCredentialsInjection(secretsJsonPath)}
1558
1582
  ` : "";
1559
1583
  const content = `#!/usr/bin/env node
1560
1584
  /**
@@ -1580,7 +1604,8 @@ async function prepareEntryCredentials(options) {
1580
1604
  workspaceAppPort = appConfig.app.port;
1581
1605
  secretsRoot = appConfig.workspaceRoot;
1582
1606
  appName = appConfig.appName;
1583
- } catch {
1607
+ } catch (error) {
1608
+ logger$8.log(`⚠️ Could not load workspace config: ${error.message}`);
1584
1609
  secretsRoot = findSecretsRoot(cwd);
1585
1610
  appName = require_config.getAppNameFromCwd(cwd) ?? void 0;
1586
1611
  }
@@ -1610,7 +1635,7 @@ async function entryDevCommand(options) {
1610
1635
  if (!(0, node_fs.existsSync)(entryPath)) throw new Error(`Entry file not found: ${entryPath}`);
1611
1636
  const defaultEnv = loadEnvFiles(".env");
1612
1637
  if (defaultEnv.loaded.length > 0) logger$8.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
1613
- const { credentials, resolvedPort, secretsJsonPath, appName } = await prepareEntryCredentials({ explicitPort: options.port });
1638
+ const { credentials, resolvedPort, secretsJsonPath, appName } = await prepareEntryCredentials({ explicitPort: options.portExplicit ? options.port : void 0 });
1614
1639
  if (appName) logger$8.log(`📦 App: ${appName} (port ${resolvedPort})`);
1615
1640
  logger$8.log(`🚀 Starting entry file: ${entry} on port ${resolvedPort}`);
1616
1641
  if (Object.keys(credentials).length > 1) logger$8.log(`🔐 Loaded ${Object.keys(credentials).length - 1} secret(s) + PORT`);
@@ -1684,12 +1709,12 @@ var EntryRunner = class {
1684
1709
  if (code !== null && code !== 0 && code !== 143) logger$8.error(`❌ Process exited with code ${code}`);
1685
1710
  this.isRunning = false;
1686
1711
  });
1687
- await new Promise((resolve$1) => setTimeout(resolve$1, 500));
1712
+ await new Promise((resolve$2) => setTimeout(resolve$2, 500));
1688
1713
  if (this.isRunning) logger$8.log(`\n🎉 Running at http://localhost:${this.port}`);
1689
1714
  }
1690
1715
  async restart() {
1691
1716
  this.stopProcess();
1692
- await new Promise((resolve$1) => setTimeout(resolve$1, 500));
1717
+ await new Promise((resolve$2) => setTimeout(resolve$2, 500));
1693
1718
  await this.runProcess();
1694
1719
  }
1695
1720
  stop() {
@@ -1761,7 +1786,7 @@ var DevServer = class {
1761
1786
  if (code !== null && code !== 0 && signal !== "SIGTERM") logger$8.error(`❌ Server exited with code ${code}`);
1762
1787
  this.isRunning = false;
1763
1788
  });
1764
- await new Promise((resolve$1) => setTimeout(resolve$1, 1e3));
1789
+ await new Promise((resolve$2) => setTimeout(resolve$2, 1e3));
1765
1790
  if (this.isRunning) {
1766
1791
  logger$8.log(`\n🎉 Server running at http://localhost:${this.actualPort}`);
1767
1792
  if (this.enableOpenApi) logger$8.log(`📚 API Docs available at http://localhost:${this.actualPort}/__docs`);
@@ -1796,7 +1821,7 @@ var DevServer = class {
1796
1821
  let attempts = 0;
1797
1822
  while (attempts < 30) {
1798
1823
  if (await isPortAvailable(portToReuse)) break;
1799
- await new Promise((resolve$1) => setTimeout(resolve$1, 100));
1824
+ await new Promise((resolve$2) => setTimeout(resolve$2, 100));
1800
1825
  attempts++;
1801
1826
  }
1802
1827
  this.requestedPort = portToReuse;
@@ -1804,9 +1829,9 @@ var DevServer = class {
1804
1829
  }
1805
1830
  async createServerEntry() {
1806
1831
  const { writeFile: fsWriteFile } = await import("node:fs/promises");
1807
- const { relative: relative$7, dirname: dirname$8 } = await import("node:path");
1832
+ const { relative: relative$6, dirname: dirname$8 } = await import("node:path");
1808
1833
  const serverPath = (0, node_path.join)(this.appRoot, ".gkm", this.provider, "server.ts");
1809
- const relativeAppPath = relative$7(dirname$8(serverPath), (0, node_path.join)(dirname$8(serverPath), "app.js"));
1834
+ const relativeAppPath = relative$6(dirname$8(serverPath), (0, node_path.join)(dirname$8(serverPath), "app.js"));
1810
1835
  const credentialsInjection = this.secretsJsonPath ? `import { Credentials } from '@geekmidas/envkit/credentials';
1811
1836
  import { existsSync, readFileSync } from 'node:fs';
1812
1837
 
@@ -1859,6 +1884,59 @@ start({
1859
1884
  await fsWriteFile(serverPath, content);
1860
1885
  }
1861
1886
  };
1887
+ /**
1888
+ * Run a command with secrets injected into Credentials.
1889
+ * Uses Node's --import flag to preload a script that populates Credentials
1890
+ * before the command loads any modules that depend on them.
1891
+ *
1892
+ * @example
1893
+ * ```bash
1894
+ * gkm exec -- npx @better-auth/cli migrate
1895
+ * gkm exec -- npx prisma migrate dev
1896
+ * ```
1897
+ */
1898
+ async function execCommand(commandArgs, options = {}) {
1899
+ const cwd = options.cwd ?? process.cwd();
1900
+ if (commandArgs.length === 0) throw new Error("No command specified. Usage: gkm exec -- <command>");
1901
+ const defaultEnv = loadEnvFiles(".env");
1902
+ if (defaultEnv.loaded.length > 0) logger$8.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
1903
+ const { credentials, secretsJsonPath, appName } = await prepareEntryCredentials({ cwd });
1904
+ if (appName) logger$8.log(`📦 App: ${appName}`);
1905
+ const secretCount = Object.keys(credentials).filter((k) => k !== "PORT").length;
1906
+ if (secretCount > 0) logger$8.log(`🔐 Loaded ${secretCount} secret(s)`);
1907
+ const preloadDir = (0, node_path.join)(cwd, ".gkm");
1908
+ await (0, node_fs_promises.mkdir)(preloadDir, { recursive: true });
1909
+ const preloadPath = (0, node_path.join)(preloadDir, "credentials-preload.ts");
1910
+ await createCredentialsPreload(preloadPath, secretsJsonPath);
1911
+ const [cmd, ...args] = commandArgs;
1912
+ if (!cmd) throw new Error("No command specified");
1913
+ logger$8.log(`🚀 Running: ${commandArgs.join(" ")}`);
1914
+ const existingNodeOptions = process.env.NODE_OPTIONS ?? "";
1915
+ const tsxImport = "--import tsx";
1916
+ const preloadImport = `--import ${preloadPath}`;
1917
+ const nodeOptions = [
1918
+ existingNodeOptions,
1919
+ tsxImport,
1920
+ preloadImport
1921
+ ].filter(Boolean).join(" ");
1922
+ const child = (0, node_child_process.spawn)(cmd, args, {
1923
+ cwd,
1924
+ stdio: "inherit",
1925
+ env: {
1926
+ ...process.env,
1927
+ ...credentials,
1928
+ NODE_OPTIONS: nodeOptions
1929
+ }
1930
+ });
1931
+ const exitCode = await new Promise((resolve$2) => {
1932
+ child.on("close", (code) => resolve$2(code ?? 0));
1933
+ child.on("error", (error) => {
1934
+ logger$8.error(`Failed to run command: ${error.message}`);
1935
+ resolve$2(1);
1936
+ });
1937
+ });
1938
+ if (exitCode !== 0) process.exit(exitCode);
1939
+ }
1862
1940
 
1863
1941
  //#endregion
1864
1942
  //#region src/build/manifests.ts
@@ -1929,10 +2007,15 @@ const logger$6 = console;
1929
2007
  async function buildCommand(options) {
1930
2008
  const loadedConfig = await require_config.loadWorkspaceConfig();
1931
2009
  if (loadedConfig.type === "workspace") {
1932
- logger$6.log("📦 Detected workspace configuration");
1933
- return workspaceBuildCommand(loadedConfig.workspace, options);
2010
+ const cwd = (0, node_path.resolve)(process.cwd());
2011
+ const workspaceRoot = (0, node_path.resolve)(loadedConfig.workspace.root);
2012
+ const isAtWorkspaceRoot = cwd === workspaceRoot;
2013
+ if (isAtWorkspaceRoot) {
2014
+ logger$6.log("📦 Detected workspace configuration");
2015
+ return workspaceBuildCommand(loadedConfig.workspace, options);
2016
+ }
1934
2017
  }
1935
- const config = await require_config.loadConfig();
2018
+ const config = loadedConfig.type === "workspace" ? (await require_config.loadAppConfig()).gkmConfig : await require_config.loadConfig();
1936
2019
  const resolved = resolveProviders(config, options);
1937
2020
  const productionConfigFromGkm = getProductionConfigFromGkm(config);
1938
2021
  const production = normalizeProductionConfig(options.production ?? false, productionConfigFromGkm);
@@ -2098,7 +2181,7 @@ async function workspaceBuildCommand(workspace, options) {
2098
2181
  try {
2099
2182
  const turboCommand = getTurboCommand(pm);
2100
2183
  logger$6.log(`Running: ${turboCommand}`);
2101
- await new Promise((resolve$1, reject) => {
2184
+ await new Promise((resolve$2, reject) => {
2102
2185
  const child = (0, node_child_process.spawn)(turboCommand, {
2103
2186
  shell: true,
2104
2187
  cwd: workspace.root,
@@ -2109,7 +2192,7 @@ async function workspaceBuildCommand(workspace, options) {
2109
2192
  }
2110
2193
  });
2111
2194
  child.on("close", (code) => {
2112
- if (code === 0) resolve$1();
2195
+ if (code === 0) resolve$2();
2113
2196
  else reject(new Error(`Turbo build failed with exit code ${code}`));
2114
2197
  });
2115
2198
  child.on("error", (err) => {
@@ -3376,26 +3459,22 @@ function getImageRef(registry, imageName, tag) {
3376
3459
  }
3377
3460
  /**
3378
3461
  * Build Docker image
3462
+ * @param imageRef - Full image reference (registry/name:tag)
3463
+ * @param appName - Name of the app (used for Dockerfile.{appName} in workspaces)
3379
3464
  */
3380
- async function buildImage(imageRef) {
3465
+ async function buildImage(imageRef, appName) {
3381
3466
  logger$4.log(`\n🔨 Building Docker image: ${imageRef}`);
3382
3467
  const cwd = process.cwd();
3383
- const inMonorepo = isMonorepo(cwd);
3384
- if (inMonorepo) logger$4.log(" Generating Dockerfile for monorepo (turbo prune)...");
3468
+ const lockfilePath = findLockfilePath(cwd);
3469
+ const lockfileDir = lockfilePath ? (0, node_path.dirname)(lockfilePath) : cwd;
3470
+ const inMonorepo = lockfileDir !== cwd;
3471
+ if (appName || inMonorepo) logger$4.log(" Generating Dockerfile for monorepo (turbo prune)...");
3385
3472
  else logger$4.log(" Generating Dockerfile...");
3386
3473
  await dockerCommand({});
3387
- let buildCwd = cwd;
3388
- let dockerfilePath = ".gkm/docker/Dockerfile";
3389
- if (inMonorepo) {
3390
- const lockfilePath = findLockfilePath(cwd);
3391
- if (lockfilePath) {
3392
- const monorepoRoot = (0, node_path.dirname)(lockfilePath);
3393
- const appRelPath = (0, node_path.relative)(monorepoRoot, cwd);
3394
- dockerfilePath = (0, node_path.join)(appRelPath, ".gkm/docker/Dockerfile");
3395
- buildCwd = monorepoRoot;
3396
- logger$4.log(` Building from monorepo root: ${monorepoRoot}`);
3397
- }
3398
- }
3474
+ const dockerfileSuffix = appName ? `.${appName}` : "";
3475
+ const dockerfilePath = `.gkm/docker/Dockerfile${dockerfileSuffix}`;
3476
+ const buildCwd = lockfilePath && (inMonorepo || appName) ? lockfileDir : cwd;
3477
+ if (buildCwd !== cwd) logger$4.log(` Building from workspace root: ${buildCwd}`);
3399
3478
  try {
3400
3479
  (0, node_child_process.execSync)(`DOCKER_BUILDKIT=1 docker build --platform linux/amd64 -f ${dockerfilePath} -t ${imageRef} .`, {
3401
3480
  cwd: buildCwd,
@@ -3432,7 +3511,7 @@ async function deployDocker(options) {
3432
3511
  const { stage, tag, skipPush, masterKey, config } = options;
3433
3512
  const imageName = config.imageName;
3434
3513
  const imageRef = getImageRef(config.registry, imageName, tag);
3435
- await buildImage(imageRef);
3514
+ await buildImage(imageRef, config.appName);
3436
3515
  if (!skipPush) if (!config.registry) logger$4.warn("\n⚠️ No registry configured. Use --skip-push or configure docker.registry in gkm.config.ts");
3437
3516
  else await pushImage(imageRef);
3438
3517
  logger$4.log("\n✅ Docker deployment ready!");
@@ -3736,7 +3815,7 @@ async function prompt(message, hidden = false) {
3736
3815
  if (!process.stdin.isTTY) throw new Error("Interactive input required. Please configure manually.");
3737
3816
  if (hidden) {
3738
3817
  process.stdout.write(message);
3739
- return new Promise((resolve$1) => {
3818
+ return new Promise((resolve$2) => {
3740
3819
  let value = "";
3741
3820
  const onData = (char) => {
3742
3821
  const c = char.toString();
@@ -3745,7 +3824,7 @@ async function prompt(message, hidden = false) {
3745
3824
  process.stdin.pause();
3746
3825
  process.stdin.removeListener("data", onData);
3747
3826
  process.stdout.write("\n");
3748
- resolve$1(value);
3827
+ resolve$2(value);
3749
3828
  } else if (c === "") {
3750
3829
  process.stdin.setRawMode(false);
3751
3830
  process.stdin.pause();
@@ -4144,11 +4223,25 @@ async function workspaceDeployCommand(workspace, options) {
4144
4223
  await provisionServices(api, project.projectId, environmentId, workspace.name, dockerServices);
4145
4224
  }
4146
4225
  const deployedAppUrls = {};
4226
+ if (!skipBuild) {
4227
+ logger$1.log("\n🏗️ Building workspace...");
4228
+ try {
4229
+ await buildCommand({
4230
+ provider: "server",
4231
+ production: true,
4232
+ stage
4233
+ });
4234
+ logger$1.log(" ✓ Workspace build complete");
4235
+ } catch (error) {
4236
+ const message = error instanceof Error ? error.message : "Unknown error";
4237
+ logger$1.log(` ✗ Workspace build failed: ${message}`);
4238
+ throw error;
4239
+ }
4240
+ }
4147
4241
  logger$1.log("\n📦 Deploying applications...");
4148
4242
  const results = [];
4149
4243
  for (const appName of appsToDeployNames) {
4150
4244
  const app = workspace.apps[appName];
4151
- const appPath = app.path;
4152
4245
  logger$1.log(`\n ${app.type === "backend" ? "⚙️" : "🌐"} Deploying ${appName}...`);
4153
4246
  try {
4154
4247
  const dokployAppName = `${workspace.name}-${appName}`;
@@ -4161,21 +4254,6 @@ async function workspaceDeployCommand(workspace, options) {
4161
4254
  if (message.includes("already exists") || message.includes("duplicate")) logger$1.log(` Application already exists`);
4162
4255
  else throw error;
4163
4256
  }
4164
- if (!skipBuild) {
4165
- logger$1.log(` Building ${appName}...`);
4166
- const originalCwd = process.cwd();
4167
- const fullAppPath = `${workspace.root}/${appPath}`;
4168
- try {
4169
- process.chdir(fullAppPath);
4170
- await buildCommand({
4171
- provider: "server",
4172
- production: true,
4173
- stage
4174
- });
4175
- } finally {
4176
- process.chdir(originalCwd);
4177
- }
4178
- }
4179
4257
  const imageName = `${workspace.name}-${appName}`;
4180
4258
  const imageRef = registry ? `${registry}/${imageName}:${imageTag}` : `${imageName}:${imageTag}`;
4181
4259
  logger$1.log(` Building Docker image: ${imageRef}`);
@@ -4185,7 +4263,8 @@ async function workspaceDeployCommand(workspace, options) {
4185
4263
  skipPush: false,
4186
4264
  config: {
4187
4265
  registry,
4188
- imageName
4266
+ imageName,
4267
+ appName
4189
4268
  }
4190
4269
  });
4191
4270
  const envVars = [`NODE_ENV=production`, `PORT=${app.port}`];
@@ -4553,7 +4632,9 @@ function generateAuthAppFiles(options) {
4553
4632
  dev: "gkm dev --entry ./src/index.ts",
4554
4633
  build: "tsc",
4555
4634
  start: "node dist/index.js",
4556
- typecheck: "tsc --noEmit"
4635
+ typecheck: "tsc --noEmit",
4636
+ "db:migrate": "gkm exec -- npx @better-auth/cli migrate",
4637
+ "db:generate": "gkm exec -- npx @better-auth/cli generate"
4557
4638
  },
4558
4639
  dependencies: {
4559
4640
  [modelsPackage]: "workspace:*",
@@ -7393,9 +7474,9 @@ async function testCommand(options = {}) {
7393
7474
  NODE_ENV: "test"
7394
7475
  }
7395
7476
  });
7396
- return new Promise((resolve$1, reject) => {
7477
+ return new Promise((resolve$2, reject) => {
7397
7478
  vitestProcess.on("close", (code) => {
7398
- if (code === 0) resolve$1();
7479
+ if (code === 0) resolve$2();
7399
7480
  else reject(new Error(`Tests failed with exit code ${code}`));
7400
7481
  });
7401
7482
  vitestProcess.on("error", (error) => {
@@ -7467,6 +7548,16 @@ program.command("dev").description("Start development server with automatic relo
7467
7548
  process.exit(1);
7468
7549
  }
7469
7550
  });
7551
+ program.command("exec").description("Run a command with secrets injected into Credentials").argument("<command...>", "Command to run (use -- before command)").action(async (commandArgs) => {
7552
+ try {
7553
+ const globalOptions = program.opts();
7554
+ if (globalOptions.cwd) process.chdir(globalOptions.cwd);
7555
+ await execCommand(commandArgs);
7556
+ } catch (error) {
7557
+ console.error(error instanceof Error ? error.message : "Command failed");
7558
+ process.exit(1);
7559
+ }
7560
+ });
7470
7561
  program.command("test").description("Run tests with secrets loaded from environment").option("--stage <stage>", "Stage to load secrets from", "development").option("--run", "Run tests once without watch mode").option("--watch", "Enable watch mode").option("--coverage", "Generate coverage report").option("--ui", "Open Vitest UI").argument("[pattern]", "Pattern to filter tests").action(async (pattern, options) => {
7471
7562
  try {
7472
7563
  const globalOptions = program.opts();