onveloz 0.0.0-beta.27 → 0.0.0-beta.28

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/index.mjs +385 -14
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -237,6 +237,192 @@ function resolveServiceSizeFromResources(cpu, memory) {
237
237
  for (const [key, tier] of Object.entries(SERVICE_SIZES)) if (tier.cpu === cpu && tier.memory === memory) return key;
238
238
  return null;
239
239
  }
240
+ /** All known flag keys. Used for validation and UI rendering. */
241
+ const PROJECT_FLAG_DEFINITIONS = {
242
+ cloudflareSaas: {
243
+ label: "Cloudflare for SaaS",
244
+ description: "SSL de domínios customizados via Cloudflare (em vez de Let's Encrypt)"
245
+ },
246
+ cloudflareTunnel: {
247
+ label: "Cloudflare Tunnel",
248
+ description: "Roteamento de tráfego via túnel Cloudflare (em vez de IP direto). Domínios customizados apontam para proxy.onveloz.com"
249
+ },
250
+ buildkit: {
251
+ label: "BuildKit",
252
+ description: "Build de imagens via BuildKit no cluster (em vez de Depot externo). Mais controle e sem dependência de serviço externo."
253
+ }
254
+ };
255
+ const PROJECT_FLAG_KEYS = Object.keys(PROJECT_FLAG_DEFINITIONS);
256
+ /**
257
+ * Allowlist of user-configurable PostgreSQL parameters with validation bounds.
258
+ * PGTune-relevant params + commonly tuned settings.
259
+ */
260
+ const PG_CONFIGURABLE_PARAMS = {
261
+ shared_buffers: {
262
+ type: "integer",
263
+ unit: "MB",
264
+ min: 16,
265
+ max: 16384,
266
+ description: "Memória dedicada para cache de dados do PostgreSQL",
267
+ requiresRestart: true
268
+ },
269
+ effective_cache_size: {
270
+ type: "integer",
271
+ unit: "MB",
272
+ min: 64,
273
+ max: 65536,
274
+ description: "Estimativa de memória disponível para cache do sistema operacional",
275
+ requiresRestart: false
276
+ },
277
+ work_mem: {
278
+ type: "integer",
279
+ unit: "MB",
280
+ min: 1,
281
+ max: 2048,
282
+ description: "Memória por operação de ordenação/hash",
283
+ requiresRestart: false
284
+ },
285
+ maintenance_work_mem: {
286
+ type: "integer",
287
+ unit: "MB",
288
+ min: 16,
289
+ max: 2048,
290
+ description: "Memória para operações de manutenção (VACUUM, CREATE INDEX)",
291
+ requiresRestart: false
292
+ },
293
+ wal_buffers: {
294
+ type: "integer",
295
+ unit: "MB",
296
+ min: 1,
297
+ max: 64,
298
+ description: "Memória para buffers de WAL",
299
+ requiresRestart: true
300
+ },
301
+ min_wal_size: {
302
+ type: "integer",
303
+ unit: "MB",
304
+ min: 32,
305
+ max: 4096,
306
+ description: "Tamanho mínimo de WAL antes de reciclar",
307
+ requiresRestart: false
308
+ },
309
+ max_wal_size: {
310
+ type: "integer",
311
+ unit: "MB",
312
+ min: 64,
313
+ max: 16384,
314
+ description: "Tamanho máximo de WAL antes de forçar checkpoint",
315
+ requiresRestart: false
316
+ },
317
+ max_connections: {
318
+ type: "integer",
319
+ min: 20,
320
+ max: 1e3,
321
+ description: "Número máximo de conexões simultâneas",
322
+ requiresRestart: true
323
+ },
324
+ random_page_cost: {
325
+ type: "real",
326
+ min: .1,
327
+ max: 10,
328
+ description: "Custo estimado de leitura aleatória de página (SSD ≈ 1.1, HDD ≈ 4.0)",
329
+ requiresRestart: false
330
+ },
331
+ effective_io_concurrency: {
332
+ type: "integer",
333
+ min: 0,
334
+ max: 1e3,
335
+ description: "Número de operações de I/O simultâneas (SSD ≈ 200)",
336
+ requiresRestart: false
337
+ },
338
+ max_worker_processes: {
339
+ type: "integer",
340
+ min: 1,
341
+ max: 128,
342
+ description: "Número máximo de processos worker",
343
+ requiresRestart: true
344
+ },
345
+ max_parallel_workers: {
346
+ type: "integer",
347
+ min: 0,
348
+ max: 128,
349
+ description: "Número máximo de workers paralelos",
350
+ requiresRestart: false
351
+ },
352
+ max_parallel_workers_per_gather: {
353
+ type: "integer",
354
+ min: 0,
355
+ max: 64,
356
+ description: "Número máximo de workers por operação Gather",
357
+ requiresRestart: false
358
+ },
359
+ max_parallel_maintenance_workers: {
360
+ type: "integer",
361
+ min: 0,
362
+ max: 64,
363
+ description: "Número máximo de workers para manutenção paralela",
364
+ requiresRestart: false
365
+ },
366
+ checkpoint_completion_target: {
367
+ type: "real",
368
+ min: .1,
369
+ max: 1,
370
+ description: "Fração do intervalo de checkpoint para completar a escrita",
371
+ requiresRestart: false
372
+ },
373
+ autovacuum_max_workers: {
374
+ type: "integer",
375
+ min: 1,
376
+ max: 16,
377
+ description: "Número máximo de processos autovacuum",
378
+ requiresRestart: true
379
+ },
380
+ autovacuum_naptime: {
381
+ type: "integer",
382
+ unit: "s",
383
+ min: 1,
384
+ max: 86400,
385
+ description: "Intervalo entre execuções do autovacuum",
386
+ requiresRestart: false
387
+ },
388
+ log_min_duration_statement: {
389
+ type: "integer",
390
+ unit: "ms",
391
+ min: -1,
392
+ max: 6e5,
393
+ description: "Log de queries mais lentas que N ms (-1 desabilita)",
394
+ requiresRestart: false
395
+ },
396
+ log_statement: {
397
+ type: "enum",
398
+ enumValues: [
399
+ "none",
400
+ "ddl",
401
+ "mod",
402
+ "all"
403
+ ],
404
+ description: "Tipos de statements que são logados",
405
+ requiresRestart: false
406
+ },
407
+ statement_timeout: {
408
+ type: "integer",
409
+ unit: "ms",
410
+ min: 0,
411
+ max: 864e5,
412
+ description: "Timeout para execução de statements (0 desabilita)",
413
+ requiresRestart: false
414
+ },
415
+ idle_in_transaction_session_timeout: {
416
+ type: "integer",
417
+ unit: "ms",
418
+ min: 0,
419
+ max: 864e5,
420
+ description: "Timeout para sessões idle em transação (0 desabilita)",
421
+ requiresRestart: false
422
+ }
423
+ };
424
+ /** All user-configurable param keys. */
425
+ const PG_CONFIGURABLE_PARAM_KEYS = Object.keys(PG_CONFIGURABLE_PARAMS);
240
426
 
241
427
  //#endregion
242
428
  //#region ../../packages/config/veloz-config.ts
@@ -1798,6 +1984,54 @@ volumesGroup.command("sync", {
1798
1984
 
1799
1985
  //#endregion
1800
1986
  //#region src/commands/config.ts
1987
+ /**
1988
+ * Sync server-side config updates back to veloz.json.
1989
+ * Maps server field names to veloz.json service config paths.
1990
+ */
1991
+ function syncConfigToVelozJson(serviceKey, updates) {
1992
+ try {
1993
+ if (!loadConfig()) return;
1994
+ patchConfig((raw) => {
1995
+ const svc = raw.services[serviceKey];
1996
+ if (!svc) return;
1997
+ for (const [field, value] of Object.entries(updates)) switch (field) {
1998
+ case "name":
1999
+ svc.name = value;
2000
+ break;
2001
+ case "buildCommand":
2002
+ if (!svc.build) svc.build = {};
2003
+ svc.build.command = value;
2004
+ break;
2005
+ case "startCommand":
2006
+ if (!svc.runtime) svc.runtime = {};
2007
+ svc.runtime.command = value;
2008
+ break;
2009
+ case "preStartCommand":
2010
+ if (!svc.runtime) svc.runtime = {};
2011
+ svc.runtime.preStartCommand = value;
2012
+ break;
2013
+ case "port":
2014
+ if (!svc.runtime) svc.runtime = {};
2015
+ svc.runtime.port = value;
2016
+ break;
2017
+ case "rootDirectory":
2018
+ svc.root = value ?? ".";
2019
+ break;
2020
+ case "instanceCount":
2021
+ if (!svc.resources) svc.resources = {};
2022
+ svc.resources.instances = value;
2023
+ break;
2024
+ case "size":
2025
+ if (!svc.resources) svc.resources = {};
2026
+ svc.resources.size = value;
2027
+ break;
2028
+ case "branch":
2029
+ svc.branch = value;
2030
+ break;
2031
+ }
2032
+ });
2033
+ } catch {}
2034
+ }
1801
2035
  function formatValue(value) {
1802
2036
  if (value === null || value === void 0 || value === "") return chalk.dim("—");
1803
2037
  return chalk.cyan(String(value));
@@ -1888,7 +2122,8 @@ configGroup.command("set", {
1888
2122
  instances: "i"
1889
2123
  },
1890
2124
  async run(c) {
1891
- const serviceId = await resolveServiceId(c.options.service);
2125
+ const { key: serviceKey, service } = await resolveService(c.options.service);
2126
+ const serviceId = service.id;
1892
2127
  const client = await getClient();
1893
2128
  const updates = {};
1894
2129
  if (c.options.name) updates.name = c.options.name;
@@ -1912,6 +2147,7 @@ configGroup.command("set", {
1912
2147
  ...updates
1913
2148
  })
1914
2149
  });
2150
+ syncConfigToVelozJson(serviceKey, updates);
1915
2151
  success("Configurações atualizadas com sucesso!");
1916
2152
  console.log(chalk.dim("\nValores atualizados:"));
1917
2153
  for (const [key, value] of Object.entries(updates)) {
@@ -1928,7 +2164,8 @@ configGroup.command("edit", {
1928
2164
  middleware: [requireAuth],
1929
2165
  options: z.object({ service: z.string().optional().describe("Serviço alvo (chave ou nome)") }),
1930
2166
  async run(c) {
1931
- const serviceId = await resolveServiceId(c.options.service);
2167
+ const { key: serviceKey, service: resolved } = await resolveService(c.options.service);
2168
+ const serviceId = resolved.id;
1932
2169
  const client = await getClient();
1933
2170
  const svc = await withSpinner({
1934
2171
  text: "Buscando configurações atuais...",
@@ -1969,6 +2206,7 @@ configGroup.command("edit", {
1969
2206
  ...updates
1970
2207
  })
1971
2208
  });
2209
+ syncConfigToVelozJson(serviceKey, updates);
1972
2210
  success("Configurações atualizadas com sucesso!");
1973
2211
  info("Execute 'veloz deploy' para aplicar as mudanças.");
1974
2212
  return { updated: updates };
@@ -1987,7 +2225,8 @@ configGroup.command("reset", {
1987
2225
  }),
1988
2226
  async run(c) {
1989
2227
  requireMcpConfirmation(c.options.userConfirmation, "resetar configurações para os padrões");
1990
- const serviceId = await resolveServiceId(c.options.service);
2228
+ const { key: serviceKey, service } = await resolveService(c.options.service);
2229
+ const serviceId = service.id;
1991
2230
  const client = await getClient();
1992
2231
  const updates = {};
1993
2232
  if (c.options.all) {
@@ -2011,6 +2250,7 @@ configGroup.command("reset", {
2011
2250
  ...updates
2012
2251
  })
2013
2252
  });
2253
+ syncConfigToVelozJson(serviceKey, updates);
2014
2254
  success("Configurações resetadas para os padrões!");
2015
2255
  info("Execute 'veloz deploy' para aplicar as mudanças.");
2016
2256
  return { reset: Object.keys(updates) };
@@ -2721,6 +2961,116 @@ dbGroup.command("tunnel", {
2721
2961
  });
2722
2962
  }
2723
2963
  });
2964
+ dbGroup.command("config", {
2965
+ description: "Ver ou alterar configuração do PostgreSQL",
2966
+ middleware: [requireAuth],
2967
+ args: z.object({ name: z.string().describe("Nome ou ID do banco de dados") }),
2968
+ options: z.object({
2969
+ set: z.string().optional().describe("Definir parâmetro (formato: chave=valor)"),
2970
+ reset: z.boolean().optional().describe("Resetar para configuração auto-tuned"),
2971
+ params: z.boolean().optional().describe("Listar parâmetros configuráveis"),
2972
+ userConfirmation: z.string().optional()
2973
+ }),
2974
+ output: z.object({
2975
+ params: z.array(z.object({
2976
+ name: z.string(),
2977
+ type: z.string(),
2978
+ unit: z.string().optional(),
2979
+ requiresRestart: z.boolean(),
2980
+ description: z.string()
2981
+ })).optional(),
2982
+ effective: z.record(z.string(), z.string()).optional(),
2983
+ userOverrides: z.record(z.string(), z.string()).optional(),
2984
+ updated: z.boolean().optional(),
2985
+ key: z.string().optional(),
2986
+ value: z.string().optional(),
2987
+ requiresRestart: z.boolean().optional(),
2988
+ reset: z.boolean().optional()
2989
+ }),
2990
+ async run(c) {
2991
+ const db = await resolveDatabaseByName(getProjectId(), c.args.name);
2992
+ const client = await getClient();
2993
+ if (c.options.params) {
2994
+ log(chalk.bold("\n Parâmetros configuráveis:\n"));
2995
+ log(` ${chalk.bold("Parâmetro".padEnd(40))}${chalk.bold("Tipo".padEnd(12))}${chalk.bold("Reinício?")}`);
2996
+ log(chalk.dim(" " + "─".repeat(65)));
2997
+ const params = Object.entries(PG_CONFIGURABLE_PARAMS).map(([key, def]) => {
2998
+ const typeLabel = def.unit ? `${def.type} (${def.unit})` : def.type;
2999
+ const restartLabel = def.requiresRestart ? chalk.yellow("Sim") : chalk.green("Não");
3000
+ log(` ${key.padEnd(40)}${typeLabel.padEnd(12)}${restartLabel}`);
3001
+ return {
3002
+ name: key,
3003
+ type: def.type,
3004
+ unit: def.unit,
3005
+ requiresRestart: def.requiresRestart,
3006
+ description: def.description
3007
+ };
3008
+ });
3009
+ log("");
3010
+ return { params };
3011
+ }
3012
+ if (db.engine !== "postgresql") throw new Error("Configuração personalizada só é suportada para PostgreSQL.");
3013
+ if (c.options.reset) {
3014
+ requireMcpConfirmation(c.options.userConfirmation, `resetar configuração do banco de dados "${db.name}" para auto-tuned`);
3015
+ if (!c.options.userConfirmation && isInteractive()) {
3016
+ if (!await promptConfirm(`Resetar toda a configuração personalizada de "${db.name}" para auto-tuned?`, false)) {
3017
+ info("Operação cancelada.");
3018
+ return {};
3019
+ }
3020
+ }
3021
+ const result = await withSpinner({
3022
+ text: "Resetando configuração...",
3023
+ fn: () => client.databases.resetConfig({ serviceId: db.id })
3024
+ });
3025
+ success("Configuração resetada para auto-tuned.");
3026
+ info("O banco de dados será reiniciado para aplicar as alterações.");
3027
+ return {
3028
+ reset: true,
3029
+ effective: result.effective
3030
+ };
3031
+ }
3032
+ if (c.options.set) {
3033
+ const eqIndex = c.options.set.indexOf("=");
3034
+ if (eqIndex === -1) throw new Error("Formato inválido. Use: --set chave=valor (ex: --set shared_buffers=512MB)");
3035
+ const key = c.options.set.slice(0, eqIndex).trim();
3036
+ const value = c.options.set.slice(eqIndex + 1).trim();
3037
+ const result = await withSpinner({
3038
+ text: `Atualizando ${key}...`,
3039
+ fn: () => client.databases.updateConfig({
3040
+ serviceId: db.id,
3041
+ config: { [key]: value }
3042
+ })
3043
+ });
3044
+ success(`${key} = ${value}`);
3045
+ if (result.requiresRestart) warn("Esta alteração requer reinício do banco de dados para ter efeito.");
3046
+ return {
3047
+ updated: true,
3048
+ key,
3049
+ value,
3050
+ requiresRestart: result.requiresRestart
3051
+ };
3052
+ }
3053
+ const config = await withSpinner({
3054
+ text: "Carregando configuração...",
3055
+ fn: () => client.databases.getConfig({ serviceId: db.id })
3056
+ });
3057
+ log(chalk.bold(`\n Configuração PostgreSQL — ${db.name}\n`));
3058
+ log(` ${chalk.bold("Parâmetro".padEnd(40))}${chalk.bold("Valor".padEnd(20))}${chalk.bold("Origem")}`);
3059
+ log(chalk.dim(" " + "─".repeat(70)));
3060
+ for (const [key, value] of Object.entries(config.effective)) {
3061
+ const isOverride = key in config.userOverrides;
3062
+ const originLabel = isOverride ? chalk.cyan("personalizado") : chalk.dim("auto-tuned");
3063
+ const valueLabel = isOverride ? chalk.cyan(value) : value;
3064
+ log(` ${key.padEnd(40)}${String(valueLabel).padEnd(20)}${originLabel}`);
3065
+ }
3066
+ if (Object.keys(config.userOverrides).length > 0) log(chalk.dim(`\n ${Object.keys(config.userOverrides).length} parâmetro(s) personalizado(s)`));
3067
+ log("");
3068
+ return {
3069
+ effective: config.effective,
3070
+ userOverrides: config.userOverrides
3071
+ };
3072
+ }
3073
+ });
2724
3074
 
2725
3075
  //#endregion
2726
3076
  //#region src/commands/template.ts
@@ -5052,6 +5402,18 @@ function extractEnvVars(files) {
5052
5402
  }
5053
5403
  return vars;
5054
5404
  }
5405
+ /**
5406
+ * Extract the major Node.js version from a package.json string's `engines.node` field.
5407
+ * Handles ranges like `>=22`, `^20`, `~18.0`, `22.x`, `20`, `>=22.0.0`.
5408
+ * Returns the major version string (e.g. "22") or undefined if not parseable.
5409
+ */
5410
+ function detectNodeVersion(pkgJsonStr) {
5411
+ const pkg = safeParsePkg(pkgJsonStr);
5412
+ if (!pkg?.engines?.node) return void 0;
5413
+ const match = pkg.engines.node.trim().match(/(\d+)/);
5414
+ if (!match) return void 0;
5415
+ return match[1];
5416
+ }
5055
5417
  function analyzeRepo(files) {
5056
5418
  const packageManager = detectPackageManager$1(files);
5057
5419
  const envVars = extractEnvVars(files);
@@ -5069,6 +5431,7 @@ function analyzeRepo(files) {
5069
5431
  const appPath = filePath.replace("/package.json", "");
5070
5432
  const appName = nested.name || appPath.split("/").pop() || appPath;
5071
5433
  let appFramework = detectFramework(content, packageManager);
5434
+ if (!appFramework && !nested.scripts?.start) continue;
5072
5435
  if (appFramework && rootPkg) {
5073
5436
  if (rootPkg.scripts?.[`build:${appName}`]) appFramework = {
5074
5437
  ...appFramework,
@@ -5086,7 +5449,8 @@ function analyzeRepo(files) {
5086
5449
  name: appName,
5087
5450
  path: appPath,
5088
5451
  framework: appFramework,
5089
- usesNodeFs: sourceEntries.some(([srcPath, fileContent]) => srcPath.startsWith(`${appPath}/`) && usesNodeFs(fileContent))
5452
+ usesNodeFs: sourceEntries.some(([srcPath, fileContent]) => srcPath.startsWith(`${appPath}/`) && usesNodeFs(fileContent)),
5453
+ nodeVersion: detectNodeVersion(content)
5090
5454
  });
5091
5455
  }
5092
5456
  return {
@@ -5095,7 +5459,8 @@ function analyzeRepo(files) {
5095
5459
  envVars,
5096
5460
  isMonorepo,
5097
5461
  monorepoApps,
5098
- usesNodeFs: sourceEntries.some(([, content]) => usesNodeFs(content))
5462
+ usesNodeFs: sourceEntries.some(([, content]) => usesNodeFs(content)),
5463
+ nodeVersion: rootPkgContent ? detectNodeVersion(rootPkgContent) : void 0
5099
5464
  };
5100
5465
  }
5101
5466
 
@@ -5318,7 +5683,7 @@ const LOGO_LINES = [
5318
5683
  ];
5319
5684
  const BRAND_COLOR = "#FF4D00";
5320
5685
  function getVersion() {
5321
- return "0.0.0-beta.27";
5686
+ return "0.0.0-beta.28";
5322
5687
  }
5323
5688
  function printBanner(subtitle) {
5324
5689
  const version = getVersion();
@@ -6342,7 +6707,7 @@ async function fetchLatestVersion() {
6342
6707
  }
6343
6708
  }
6344
6709
  function getCurrentVersion() {
6345
- return "0.0.0-beta.27";
6710
+ return "0.0.0-beta.28";
6346
6711
  }
6347
6712
  /**
6348
6713
  * Install a specific CLI version. Returns true on success.
@@ -6920,7 +7285,8 @@ async function createServiceFlow(projectId, projectName, repoName, opts = {}) {
6920
7285
  buildCommand: a.framework?.buildCommand ?? null,
6921
7286
  startCommand: a.framework?.startCommand ?? null,
6922
7287
  port: a.framework?.port ?? 3e3,
6923
- usesNodeFs: a.usesNodeFs
7288
+ usesNodeFs: a.usesNodeFs,
7289
+ nodeVersion: a.nodeVersion
6924
7290
  }));
6925
7291
  let selectedApps;
6926
7292
  if (opts.yes) if (opts.app) {
@@ -6987,7 +7353,8 @@ async function createServiceFlow(projectId, projectName, repoName, opts = {}) {
6987
7353
  buildCommand: app.buildCommand ?? void 0,
6988
7354
  startCommand: app.startCommand ?? void 0,
6989
7355
  port: app.port ?? 3e3,
6990
- framework: app.framework ?? void 0
7356
+ framework: app.framework ?? void 0,
7357
+ nodeVersion: app.nodeVersion
6991
7358
  }))
6992
7359
  });
6993
7360
  success(`Serviço criado: ${chalk.bold(service$1.name)}`);
@@ -7079,7 +7446,8 @@ async function createServiceFlow(projectId, projectName, repoName, opts = {}) {
7079
7446
  buildCommand: settings.buildCommand ?? void 0,
7080
7447
  startCommand: settings.startCommand ?? void 0,
7081
7448
  port: settings.port,
7082
- framework: settings.framework ?? void 0
7449
+ framework: settings.framework ?? void 0,
7450
+ nodeVersion: detection.nodeVersion
7083
7451
  }))
7084
7452
  });
7085
7453
  success(`Serviço criado: ${chalk.bold(service.name)}`);
@@ -7197,7 +7565,8 @@ async function addServiceFlow(existingConfig, opts) {
7197
7565
  buildCommand: a.framework?.buildCommand ?? null,
7198
7566
  startCommand: a.framework?.startCommand ?? null,
7199
7567
  port: a.framework?.port ?? 3e3,
7200
- usesNodeFs: a.usesNodeFs
7568
+ usesNodeFs: a.usesNodeFs,
7569
+ nodeVersion: a.nodeVersion
7201
7570
  }));
7202
7571
  const availableApps = allApps.filter((a) => !existingRoots.has(a.root));
7203
7572
  if (availableApps.length === 0) {
@@ -7271,7 +7640,8 @@ async function addServiceFlow(existingConfig, opts) {
7271
7640
  buildCommand: hasDockerfile ? void 0 : app.buildCommand ?? void 0,
7272
7641
  startCommand: hasDockerfile ? void 0 : app.startCommand ?? void 0,
7273
7642
  port: app.port ?? 3e3,
7274
- framework: hasDockerfile ? "docker" : app.framework ?? void 0
7643
+ framework: hasDockerfile ? "docker" : app.framework ?? void 0,
7644
+ nodeVersion: hasDockerfile ? void 0 : app.nodeVersion
7275
7645
  }))
7276
7646
  });
7277
7647
  success(`Serviço criado: ${chalk.bold(service$1.name)}`);
@@ -7382,7 +7752,8 @@ async function addServiceFlow(existingConfig, opts) {
7382
7752
  buildCommand: settings.buildCommand ?? void 0,
7383
7753
  startCommand: settings.startCommand ?? void 0,
7384
7754
  port: settings.port,
7385
- framework: settings.framework ?? void 0
7755
+ framework: settings.framework ?? void 0,
7756
+ nodeVersion: detection.nodeVersion
7386
7757
  }))
7387
7758
  });
7388
7759
  success(`Serviço criado: ${chalk.bold(service.name)}`);
@@ -8016,7 +8387,7 @@ function registerUpdate(cli$1) {
8016
8387
  //#region src/index.ts
8017
8388
  if (process.argv.includes("--mcp")) process.env.VELOZ_MCP = "true";
8018
8389
  const cli = Cli.create("veloz", {
8019
- version: "0.0.0-beta.27",
8390
+ version: "0.0.0-beta.28",
8020
8391
  description: "CLI da plataforma Veloz — deploy rápido para o Brasil",
8021
8392
  env: z.object({ VELOZ_ENV: z.string().optional().describe("Ambiente alvo (ex: preview, staging)") }),
8022
8393
  mcp: { command: "npx -y onveloz --mcp" }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "onveloz",
3
- "version": "0.0.0-beta.27",
3
+ "version": "0.0.0-beta.28",
4
4
  "description": "CLI da plataforma Veloz — deploy rápido para o Brasil",
5
5
  "keywords": [
6
6
  "brasil",