@neetru/cli 2.1.1 → 2.3.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.js CHANGED
@@ -1,15 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
3
  import { log } from './utils/logger.js';
4
+ import { CLI_VERSION } from './version.js';
4
5
  const program = new Command();
5
6
  program
6
7
  .name('neetru')
7
- .description('Neetru Developer Kit scaffold, AI assistant e deploy para produtos SaaS')
8
- .version('2.0.0');
8
+ .description('Operar o Neetru Developer Kit (scaffold, AI, deploy)')
9
+ .version(CLI_VERSION);
9
10
  // ── neetru ai ─────────────────────────────────────────────────────────
10
11
  program
11
12
  .command('ai')
12
- .description('REPL interativo com IA Neetru-aware (Claude / OpenAI / Gemini)')
13
+ .description('Abrir REPL de IA Neetru-aware (Claude/OpenAI/Gemini)')
13
14
  .option('-m, --model <model>', 'modelo: claude | openai | gemini | auto', 'auto')
14
15
  .action(async (opts) => {
15
16
  const { runAiRepl } = await import('./commands/ai.js');
@@ -19,7 +20,7 @@ program
19
20
  // v2.1.1 — prompt interativo de caminho + merge mode + preserva arquivos
20
21
  program
21
22
  .command('init <name>')
22
- .description('Scaffold de novo produto SaaS Neetru (interativo — escolhe new subdir | merge cwd | custom path)')
23
+ .description('Inicializar scaffold de produto SaaS Neetru')
23
24
  .option('--type <type>', 'nextjs | node-api', 'nextjs')
24
25
  .option('--here', 'init no cwd atual (modo merge — preserva existentes)')
25
26
  .option('--path <path>', 'custom path target')
@@ -36,27 +37,80 @@ program
36
37
  yes: opts.yes,
37
38
  });
38
39
  });
40
+ // ── neetru new (macro end-to-end) ─────────────────────────────────────
41
+ // Cria produto + workspace + scaffold local + abre painel — single command.
42
+ program
43
+ .command('new <name>')
44
+ .description('Criar produto, workspace, scaffold e abrir painel')
45
+ .option('--product-slug <slug>', 'slug do produto (default: derivado de <name>)')
46
+ .option('--env <env>', 'dev (default) | staging | prod', 'dev')
47
+ .option('--tier <tier>', 'standard (default) | dev | enterprise', 'standard')
48
+ .option('--customer <customerId>', 'customerId dono do workspace (default: self)')
49
+ .option('--skip-init', 'pula o scaffold local')
50
+ .option('--skip-open', 'pula a abertura do browser')
51
+ .option('--json', 'saída em JSON (machine-readable)')
52
+ .action(async (name, opts) => {
53
+ const { runNewMacro } = await import('./commands/new.js');
54
+ await runNewMacro(name, {
55
+ productSlug: opts.productSlug,
56
+ env: opts.env,
57
+ tier: opts.tier,
58
+ customer: opts.customer,
59
+ skipInit: !!opts.skipInit,
60
+ skipOpen: !!opts.skipOpen,
61
+ json: !!opts.json,
62
+ });
63
+ });
64
+ // ── neetru auth ───────────────────────────────────────────────────────
65
+ // Wave D — detecta Claude Code/Codex/Gemini instalados e reaproveita creds.
66
+ const authCmd = program
67
+ .command('auth')
68
+ .description('Gerenciar credenciais de IA (Claude, Codex, Gemini)');
69
+ authCmd
70
+ .command('status')
71
+ .description('Listar provedores detectados e estado das credenciais')
72
+ .option('--json', 'saída JSON')
73
+ .action(async (opts) => {
74
+ const { runAuthStatus } = await import('./commands/auth.js');
75
+ await runAuthStatus({ json: !!opts.json });
76
+ });
77
+ authCmd
78
+ .command('setup')
79
+ .description('Wizard interativo: detectar, instalar, configurar')
80
+ .option('--json', 'modo não-interativo (equivalente a pull)')
81
+ .action(async (opts) => {
82
+ const { runAuthSetup } = await import('./commands/auth.js');
83
+ await runAuthSetup({ json: !!opts.json });
84
+ });
85
+ authCmd
86
+ .command('pull')
87
+ .description('Copiar creds dos CLIs detectados pra config do Neetru')
88
+ .option('--json', 'saída JSON')
89
+ .action(async (opts) => {
90
+ const { runAuthPull } = await import('./commands/auth.js');
91
+ await runAuthPull({ json: !!opts.json });
92
+ });
39
93
  // ── neetru config ─────────────────────────────────────────────────────
40
94
  const configCmd = program
41
95
  .command('config')
42
- .description('Gerenciar configurações do CLI (chaves de API, modelo padrão)');
96
+ .description('Gerenciar configurações do CLI');
43
97
  configCmd
44
98
  .command('set <key> <value>')
45
- .description('Define uma configuração')
99
+ .description('Definir valor de configuração')
46
100
  .action(async (key, value) => {
47
101
  const { configSet } = await import('./commands/config.js');
48
102
  configSet(key, value);
49
103
  });
50
104
  configCmd
51
105
  .command('get [key]')
52
- .description(' configuração(ões)')
106
+ .description('Ler configuração por chave (ou todas)')
53
107
  .action(async (key) => {
54
108
  const { configGet } = await import('./commands/config.js');
55
109
  configGet(key);
56
110
  });
57
111
  configCmd
58
112
  .command('path')
59
- .description('Mostra o caminho do arquivo de configuração')
113
+ .description('Mostrar caminho do arquivo de configuração')
60
114
  .action(async () => {
61
115
  const { configPath } = await import('./commands/config.js');
62
116
  configPath();
@@ -64,7 +118,7 @@ configCmd
64
118
  // ── neetru login ──────────────────────────────────────────────────────
65
119
  program
66
120
  .command('login')
67
- .description('Autentica o CLI via Device Code OAuth (RFC 8628)')
121
+ .description('Autenticar CLI via Device Code OAuth (RFC 8628)')
68
122
  .option('--token <token>', 'token nrt_<keyId>_<secret> (modo CI/legado, pula browser)')
69
123
  .option('--json', 'saída em JSON (machine-readable)')
70
124
  .action(async (opts) => {
@@ -74,7 +128,7 @@ program
74
128
  // ── neetru logout ─────────────────────────────────────────────────────
75
129
  program
76
130
  .command('logout')
77
- .description('Apaga as credenciais locais (~/.config/neetru-cli/auth.json + cache legado)')
131
+ .description('Remover credenciais locais do CLI')
78
132
  .action(async () => {
79
133
  const { runLogout } = await import('./commands/logout.js');
80
134
  await runLogout();
@@ -82,7 +136,7 @@ program
82
136
  // ── neetru whoami ─────────────────────────────────────────────────────
83
137
  program
84
138
  .command('whoami')
85
- .description('Mostra a identidade da chave CLI corrente')
139
+ .description('Mostrar identidade da chave CLI corrente')
86
140
  .option('--json', 'saída em JSON')
87
141
  .action(async (opts) => {
88
142
  const { runWhoami } = await import('./commands/whoami.js');
@@ -91,7 +145,7 @@ program
91
145
  // ── neetru build ──────────────────────────────────────────────────────
92
146
  program
93
147
  .command('build')
94
- .description('Empacota o produto no diretório atual num tarball pronto para deploy')
148
+ .description('Construir tarball do produto pronto para deploy')
95
149
  .option('--product <slug>', 'override do slug (default: lê neetru.config.json)')
96
150
  .option('--stack <stack>', 'node | docker | php-apache | static (default: detectado)')
97
151
  .option('--output <dir>', 'diretório de saída', '.neetru-build')
@@ -110,7 +164,7 @@ program
110
164
  // ── neetru deploy ─────────────────────────────────────────────────────
111
165
  program
112
166
  .command('deploy')
113
- .description('Deploy do produto via pipeline Neetru Core (interativo por default)')
167
+ .description('Deployar produto via pipeline do Neetru Core')
114
168
  .option('--product <slug>', 'slug do produto')
115
169
  .option('--version <version>', 'versão a deployar')
116
170
  .option('--stack <stack>', 'node | docker | php-apache | static')
@@ -149,7 +203,7 @@ program
149
203
  // delega ao status de workspace legado (backward-compat).
150
204
  program
151
205
  .command('status')
152
- .description('Saúde das superfícies públicas (landing/api/portal/políticas). --client-id = status de workspace')
206
+ .description('Verificar saúde das superfícies públicas do Core')
153
207
  .option('--client-id <id>', 'oauthClientId do workspace (status de workspace legado)')
154
208
  .option('--json', 'saída em JSON')
155
209
  .action(async (opts) => {
@@ -159,10 +213,10 @@ program
159
213
  // ── neetru tenants ────────────────────────────────────────────────────
160
214
  const tenantsCmd = program
161
215
  .command('tenants')
162
- .description('Control plane — inspeção de tenants (read-only)');
216
+ .description('Gerenciar tenants (read-only)');
163
217
  tenantsCmd
164
218
  .command('list')
165
- .description('Lista tenants (filtros --status / --product)')
219
+ .description('Listar tenants')
166
220
  .option('--status <status>', 'ativo | em provisionamento | suspenso | arquivado')
167
221
  .option('--product <productId>', 'filtra por productId')
168
222
  .option('--limit <n>', 'máximo de resultados (default 100, max 500)')
@@ -178,7 +232,7 @@ tenantsCmd
178
232
  });
179
233
  tenantsCmd
180
234
  .command('get <id>')
181
- .description('Detalha um tenant pelo ID')
235
+ .description('Mostrar detalhes de um tenant')
182
236
  .option('--json', 'saída em JSON')
183
237
  .action(async (id, opts) => {
184
238
  const { runTenantsGet } = await import('./commands/tenants.js');
@@ -186,7 +240,7 @@ tenantsCmd
186
240
  });
187
241
  tenantsCmd
188
242
  .command('create')
189
- .description('Cria um tenant (status inicial: em provisionamento)')
243
+ .description('Criar tenant (status inicial: em provisionamento)')
190
244
  .requiredOption('--name <name>', 'nome do tenant')
191
245
  .requiredOption('--slug <slug>', 'slug do tenant')
192
246
  .requiredOption('--customer <customerId>', 'id do customer')
@@ -208,7 +262,7 @@ tenantsCmd
208
262
  });
209
263
  tenantsCmd
210
264
  .command('update <id>')
211
- .description('Atualiza dados de um tenant existente')
265
+ .description('Atualizar dados de um tenant')
212
266
  .requiredOption('--name <name>', 'nome do tenant')
213
267
  .requiredOption('--slug <slug>', 'slug do tenant')
214
268
  .requiredOption('--customer <customerId>', 'id do customer')
@@ -230,7 +284,7 @@ tenantsCmd
230
284
  });
231
285
  tenantsCmd
232
286
  .command('suspend <id>')
233
- .description('Suspende um tenant (destrutivo — confirmação interativa)')
287
+ .description('Suspender tenant (destrutivo — exige confirmação)')
234
288
  .option('--yes', 'pula a confirmação interativa (modo script)')
235
289
  .option('--force', 'alias de --yes')
236
290
  .option('--json', 'saída em JSON')
@@ -240,7 +294,7 @@ tenantsCmd
240
294
  });
241
295
  tenantsCmd
242
296
  .command('reactivate <id>')
243
- .description('Reativa um tenant suspenso')
297
+ .description('Reativar tenant suspenso')
244
298
  .option('--json', 'saída em JSON')
245
299
  .action(async (id, opts) => {
246
300
  const { runTenantsReactivate } = await import('./commands/tenants.js');
@@ -249,10 +303,10 @@ tenantsCmd
249
303
  // ── neetru audit ──────────────────────────────────────────────────────
250
304
  const auditCmd = program
251
305
  .command('audit')
252
- .description('Control plane — trilha de auditoria do Core (read-only)');
306
+ .description('Consultar trilha de auditoria do Core (read-only)');
253
307
  auditCmd
254
308
  .command('tail')
255
- .description('Últimos N eventos de audit_logs (mais recente primeiro)')
309
+ .description('Listar últimos eventos de audit_logs')
256
310
  .option('-n, --limit <n>', 'número de eventos (default 50, max 200)')
257
311
  .option('--action <substring>', 'filtra por substring da ação (ex: billing, tenant.create)')
258
312
  .option('--severity <level>', 'info | warning | critical')
@@ -271,10 +325,10 @@ auditCmd
271
325
  // ── neetru billing ────────────────────────────────────────────────────
272
326
  const billingCmd = program
273
327
  .command('billing')
274
- .description('Control plane billing/contabilidade (read-only)');
328
+ .description('Consultar billing e contabilidade (read-only)');
275
329
  billingCmd
276
330
  .command('summary')
277
- .description('Sumário contábil do mês corrente (MRR, invoices, subscriptions)')
331
+ .description('Mostrar sumário contábil do mês (MRR, invoices, subs)')
278
332
  .option('--year <YYYY>', 'ano (default: corrente)')
279
333
  .option('--month <1-12>', 'mês (default: corrente)')
280
334
  .option('--json', 'saída em JSON')
@@ -285,10 +339,10 @@ billingCmd
285
339
  // ── neetru servers ────────────────────────────────────────────────────
286
340
  const serversCmd = program
287
341
  .command('servers')
288
- .description('Control plane inventário de servers (read-only)');
342
+ .description('Gerenciar servers e inventário de VMs');
289
343
  serversCmd
290
344
  .command('list')
291
- .description('Lista servers (filtros --status / --provider / --capacity)')
345
+ .description('Listar servers')
292
346
  .option('--status <status>', 'online (operacional + heartbeat fresco)')
293
347
  .option('--provider <provider>', 'hetzner | digitalocean | aws | ...')
294
348
  .option('--capacity', 'inclui colunas de RAM/CPU/disco')
@@ -304,7 +358,7 @@ serversCmd
304
358
  });
305
359
  serversCmd
306
360
  .command('provision')
307
- .description('Provisiona uma VM GCP (admin only) — cria server + registration token')
361
+ .description('Provisionar VM GCP e gerar registration token (admin)')
308
362
  .requiredOption('--name <name>', 'nome do servidor')
309
363
  .requiredOption('--zone <zone>', 'zona GCP (ex: us-central1-a)')
310
364
  .requiredOption('--machine-type <type>', 'machine type GCP (ex: e2-small)')
@@ -324,7 +378,7 @@ serversCmd
324
378
  });
325
379
  serversCmd
326
380
  .command('deactivate <serverId>')
327
- .description('Desativa um server (destrutivo top-tier — confirmação + step-up MFA)')
381
+ .description('Desativar server (destrutivo top-tier — exige MFA)')
328
382
  .option('--yes', 'pula a confirmação interativa (modo script)')
329
383
  .option('--force', 'alias de --yes')
330
384
  .option('--dry-run', 'valida e mostra o efeito sem aplicar')
@@ -342,7 +396,7 @@ serversCmd
342
396
  });
343
397
  serversCmd
344
398
  .command('dispatch <serverId> <commandType>')
345
- .description('Enfileira um comando pro agente Linux do server')
399
+ .description('Enfileirar comando para o agente Linux do server')
346
400
  .option('--params <json>', 'objeto JSON de params do comando')
347
401
  .option('--json', 'saída em JSON')
348
402
  .action(async (id, commandType, opts) => {
@@ -352,10 +406,10 @@ serversCmd
352
406
  // ── neetru workspaces ─────────────────────────────────────────────────
353
407
  const workspacesCmd = program
354
408
  .command('workspaces')
355
- .description('Control plane — runtime shared de workspaces');
409
+ .description('Gerenciar workspaces compartilhados');
356
410
  workspacesCmd
357
411
  .command('create')
358
- .description('Cria um workspace (devolve OAuth client secret one-time)')
412
+ .description('Criar workspace (retorna OAuth secret one-time)')
359
413
  .requiredOption('--product <productId>', 'id do produto')
360
414
  .requiredOption('--customer <customerId>', 'id do customer')
361
415
  .requiredOption('--env <env>', 'dev | staging | prod')
@@ -375,7 +429,7 @@ workspacesCmd
375
429
  });
376
430
  workspacesCmd
377
431
  .command('advance <workspaceId>')
378
- .description('Promove uma versão de bundle pra "running" no workspace')
432
+ .description('Promover versão de bundle para running no workspace')
379
433
  .requiredOption('--product <slug>', 'productSlug do bundle')
380
434
  .requiredOption('--version <version>', 'versão do bundle a ativar')
381
435
  .option('--json', 'saída em JSON')
@@ -387,13 +441,44 @@ workspacesCmd
387
441
  json: !!opts.json,
388
442
  });
389
443
  });
444
+ workspacesCmd
445
+ .command('list')
446
+ .description('Listar workspaces')
447
+ .option('--product <productId>', 'filtra por productId')
448
+ .option('--env <env>', 'dev | staging | prod')
449
+ .option('--status <status>', 'active | paused | provisioning | …')
450
+ .option('--json', 'saída em JSON')
451
+ .action(async (opts) => {
452
+ const { runWorkspacesList } = await import('./commands/workspaces.js');
453
+ await runWorkspacesList({
454
+ product: opts.product,
455
+ env: opts.env,
456
+ status: opts.status,
457
+ json: !!opts.json,
458
+ });
459
+ });
460
+ workspacesCmd
461
+ .command('get <workspaceId>')
462
+ .description('Mostrar detalhes de um workspace')
463
+ .option('--json', 'saída em JSON')
464
+ .action(async (id, opts) => {
465
+ const { runWorkspacesGet } = await import('./commands/workspaces.js');
466
+ await runWorkspacesGet(id, { json: !!opts.json });
467
+ });
468
+ workspacesCmd
469
+ .command('open <workspaceId>')
470
+ .description('Abrir painel do workspace no browser')
471
+ .action(async (id) => {
472
+ const { runWorkspacesOpen } = await import('./commands/workspaces.js');
473
+ await runWorkspacesOpen(id);
474
+ });
390
475
  // ── neetru deployments ────────────────────────────────────────────────
391
476
  const deploymentsCmd = program
392
477
  .command('deployments')
393
- .description('Control plane — recurso deployments/ (paridade com a UI)');
478
+ .description('Gerenciar deployments do Core');
394
479
  deploymentsCmd
395
480
  .command('create')
396
- .description('Cria um deployment (dispara comando deploy pro agente)')
481
+ .description('Criar deployment (dispara comando para o agente)')
397
482
  .requiredOption('--product <productId>', 'id do produto')
398
483
  .requiredOption('--tenant <tenantId>', 'id do tenant alvo')
399
484
  .requiredOption('--version <version>', 'versão a deployar')
@@ -413,7 +498,7 @@ deploymentsCmd
413
498
  });
414
499
  deploymentsCmd
415
500
  .command('rollback <deploymentId>')
416
- .description('Rollback de um deployment (destrutivo top-tier — confirmação + step-up MFA)')
501
+ .description('Reverter deployment (destrutivo top-tier — exige MFA)')
417
502
  .option('--yes', 'pula a confirmação interativa (modo script)')
418
503
  .option('--force', 'alias de --yes')
419
504
  .option('--dry-run', 'valida e mostra o efeito sem aplicar')
@@ -432,10 +517,10 @@ deploymentsCmd
432
517
  // ── neetru cloud-run ──────────────────────────────────────────────────
433
518
  const cloudRunCmd = program
434
519
  .command('cloud-run')
435
- .description('Control plane — serviços Cloud Run (admin only)');
520
+ .description('Gerenciar serviços Cloud Run (admin)');
436
521
  cloudRunCmd
437
522
  .command('pause <service>')
438
- .description('Pausa um serviço Cloud Run (scale-to-zero)')
523
+ .description('Pausar serviço Cloud Run (scale-to-zero)')
439
524
  .option('--json', 'saída em JSON')
440
525
  .action(async (service, opts) => {
441
526
  const { runCloudRunPause } = await import('./commands/cloud-run.js');
@@ -443,7 +528,7 @@ cloudRunCmd
443
528
  });
444
529
  cloudRunCmd
445
530
  .command('resume <service>')
446
- .description('Retoma um serviço Cloud Run pausado')
531
+ .description('Retomar serviço Cloud Run pausado')
447
532
  .option('--min-instances <n>', 'minInstanceCount')
448
533
  .option('--max-instances <n>', 'maxInstanceCount')
449
534
  .option('--json', 'saída em JSON')
@@ -457,7 +542,7 @@ cloudRunCmd
457
542
  });
458
543
  cloudRunCmd
459
544
  .command('delete <service>')
460
- .description('Exclui um serviço Cloud Run (IRREVERSÍVEL — confirmação + step-up MFA)')
545
+ .description('Remover serviço Cloud Run (IRREVERSÍVEL — exige MFA)')
461
546
  .option('--yes', 'pula a confirmação interativa (modo script)')
462
547
  .option('--force', 'alias de --yes')
463
548
  .option('--dry-run', 'valida e mostra o efeito sem aplicar')
@@ -476,10 +561,10 @@ cloudRunCmd
476
561
  // ── neetru api-catalog ────────────────────────────────────────────────
477
562
  const apiCatalogCmd = program
478
563
  .command('api-catalog')
479
- .description('Control plane — registry de APIs versionadas (apis/)');
564
+ .description('Gerenciar catálogo de APIs versionadas');
480
565
  apiCatalogCmd
481
566
  .command('create <slug>')
482
- .description('Registra uma nova API no catálogo')
567
+ .description('Registrar nova API no catálogo')
483
568
  .requiredOption('--name <name>', 'nome da API')
484
569
  .requiredOption('--base-url <url>', 'base URL')
485
570
  .requiredOption('--version <version>', 'versão')
@@ -509,7 +594,7 @@ apiCatalogCmd
509
594
  });
510
595
  apiCatalogCmd
511
596
  .command('update <slug>')
512
- .description('Atualiza uma entrada do catálogo (slug é imutável)')
597
+ .description('Atualizar entrada do catálogo (slug imutável)')
513
598
  .requiredOption('--name <name>', 'nome da API')
514
599
  .requiredOption('--base-url <url>', 'base URL')
515
600
  .requiredOption('--version <version>', 'versão')
@@ -539,7 +624,7 @@ apiCatalogCmd
539
624
  });
540
625
  apiCatalogCmd
541
626
  .command('archive <slug>')
542
- .description('Soft-delete de uma API (--unarchive reativa)')
627
+ .description('Arquivar API por soft-delete (--unarchive reverte)')
543
628
  .option('--unarchive', 'reativa em vez de arquivar')
544
629
  .option('--yes', 'pula a confirmação interativa (modo script)')
545
630
  .option('--force', 'alias de --yes')
@@ -555,7 +640,7 @@ apiCatalogCmd
555
640
  });
556
641
  apiCatalogCmd
557
642
  .command('delete <slug>')
558
- .description('Delete físico de uma API (IRREVERSÍVEL — confirmação + step-up MFA)')
643
+ .description('Remover API fisicamente (IRREVERSÍVEL — exige MFA)')
559
644
  .option('--yes', 'pula a confirmação interativa (modo script)')
560
645
  .option('--force', 'alias de --yes')
561
646
  .option('--dry-run', 'valida e mostra o efeito sem aplicar')
@@ -574,10 +659,10 @@ apiCatalogCmd
574
659
  // ── neetru products ───────────────────────────────────────────────────
575
660
  const productsCmd = program
576
661
  .command('products')
577
- .description('Control plane — registry interno de produtos SaaS (read-only)');
662
+ .description('Gerenciar registry de produtos SaaS internos');
578
663
  productsCmd
579
664
  .command('list')
580
- .description('Lista produtos internos (registry products/, filtro --status)')
665
+ .description('Listar produtos internos')
581
666
  .option('--status <status>', 'ativo | beta | descontinuado')
582
667
  .option('--limit <n>', 'máximo de resultados (default 100, max 500)')
583
668
  .option('--json', 'saída em JSON')
@@ -585,9 +670,33 @@ productsCmd
585
670
  const { runProductsList } = await import('./commands/products.js');
586
671
  await runProductsList({ status: opts.status, limit: opts.limit, json: !!opts.json });
587
672
  });
673
+ productsCmd
674
+ .command('create')
675
+ .description('Criar produto SaaS interno (interativo por default)')
676
+ .option('--name <name>', 'nome do produto (interativo se ausente)')
677
+ .option('--slug <slug>', 'slug (auto-derivado de --name se ausente)')
678
+ .option('--description <text>', 'descrição (opcional)')
679
+ .option('--owner-team <team>', 'time dono (default: neetru-eng)')
680
+ .option('--plan-template <tier>', 'free | starter | pro (default: free)')
681
+ .option('--env <csv>', 'ambientes separados por vírgula (default: dev,prod)')
682
+ .option('--yes', 'pula prompts (exige --name; resto usa defaults)')
683
+ .option('--json', 'saída em JSON (machine-readable)')
684
+ .action(async (opts) => {
685
+ const { runProductsCreate } = await import('./commands/products.js');
686
+ await runProductsCreate({
687
+ name: opts.name,
688
+ slug: opts.slug,
689
+ description: opts.description,
690
+ ownerTeam: opts.ownerTeam,
691
+ planTemplate: opts.planTemplate,
692
+ env: opts.env,
693
+ yes: !!opts.yes,
694
+ json: !!opts.json,
695
+ });
696
+ });
588
697
  productsCmd
589
698
  .command('publish <slug>')
590
- .description('Publica um produto no catálogo público (published=true)')
699
+ .description('Publicar produto no catálogo público')
591
700
  .option('--json', 'saída em JSON')
592
701
  .action(async (slug, opts) => {
593
702
  const { runProductsPublish } = await import('./commands/products.js');
@@ -595,7 +704,7 @@ productsCmd
595
704
  });
596
705
  productsCmd
597
706
  .command('unpublish <slug>')
598
- .description('Remove um produto do catálogo público (published=false)')
707
+ .description('Remover produto do catálogo público')
599
708
  .option('--json', 'saída em JSON')
600
709
  .action(async (slug, opts) => {
601
710
  const { runProductsUnpublish } = await import('./commands/products.js');
@@ -604,10 +713,10 @@ productsCmd
604
713
  // ── neetru products db (Phase A — per-product DB isolation) ────────────
605
714
  const productsDbCmd = productsCmd
606
715
  .command('db')
607
- .description('Bancos de dados isolados por produto (firestore-instance | cloud-sql-* | vm-*)');
716
+ .description('Gerenciar bancos isolados por produto');
608
717
  productsDbCmd
609
718
  .command('list')
610
- .description('Lista bancos. Filtros: --product-id, --engine, --status')
719
+ .description('Listar bancos de produtos')
611
720
  .option('--product-id <id>')
612
721
  .option('--engine <engine>')
613
722
  .option('--status <status>')
@@ -623,7 +732,7 @@ productsDbCmd
623
732
  });
624
733
  productsDbCmd
625
734
  .command('engines')
626
- .description('Lista engines suportados')
735
+ .description('Listar engines de banco suportados')
627
736
  .option('--json')
628
737
  .action(async (opts) => {
629
738
  const { runDbEngines } = await import('./commands/products-db.js');
@@ -631,7 +740,7 @@ productsDbCmd
631
740
  });
632
741
  productsDbCmd
633
742
  .command('create')
634
- .description('Cria um banco (Phase A: registra + audit; provisionamento real é Phase B)')
743
+ .description('Criar banco de produto (Phase A: registra + audit)')
635
744
  .requiredOption('--product-id <id>')
636
745
  .requiredOption('--label <label>')
637
746
  .requiredOption('--engine <engine>', 'firestore-instance|cloud-sql-postgres|cloud-sql-mysql|vm-postgres-single|vm-postgres-cluster|vm-mysql-single|vm-mysql-cluster')
@@ -655,7 +764,7 @@ productsDbCmd
655
764
  });
656
765
  productsDbCmd
657
766
  .command('get <id>')
658
- .description('Detalhes de um banco')
767
+ .description('Mostrar detalhes de um banco')
659
768
  .option('--json')
660
769
  .action(async (id, opts) => {
661
770
  const { runDbGet } = await import('./commands/products-db.js');
@@ -663,7 +772,7 @@ productsDbCmd
663
772
  });
664
773
  productsDbCmd
665
774
  .command('status <id> <status>')
666
- .description('Atualiza status (requested|provisioning|active|degraded|failed|archived)')
775
+ .description('Atualizar status de um banco de produto')
667
776
  .option('--reason <text>')
668
777
  .option('--json')
669
778
  .action(async (id, status, opts) => {
@@ -672,7 +781,7 @@ productsDbCmd
672
781
  });
673
782
  productsDbCmd
674
783
  .command('retry <id>')
675
- .description('Re-enfileira provisionamento (status failed/degraded → requested)')
784
+ .description('Reenfileirar provisionamento de banco')
676
785
  .option('--json')
677
786
  .action(async (id, opts) => {
678
787
  const { runDbRetry } = await import('./commands/products-db.js');
@@ -680,7 +789,7 @@ productsDbCmd
680
789
  });
681
790
  productsDbCmd
682
791
  .command('rotate <id>')
683
- .description('Rotaciona credenciais (admin; Phase A: intent + audit)')
792
+ .description('Rotacionar credenciais do banco (admin)')
684
793
  .option('--json')
685
794
  .action(async (id, opts) => {
686
795
  const { runDbRotate } = await import('./commands/products-db.js');
@@ -688,7 +797,7 @@ productsDbCmd
688
797
  });
689
798
  productsDbCmd
690
799
  .command('delete <id>')
691
- .description('Arquiva o banco (soft-delete; admin)')
800
+ .description('Arquivar banco por soft-delete (admin)')
692
801
  .option('--json')
693
802
  .action(async (id, opts) => {
694
803
  const { runDbDelete } = await import('./commands/products-db.js');
@@ -697,7 +806,7 @@ productsDbCmd
697
806
  // ── neetru logs ───────────────────────────────────────────────────────
698
807
  program
699
808
  .command('logs')
700
- .description('Visualiza logs do workspace; suporta tail contínuo')
809
+ .description('Visualizar logs do workspace (suporta tail contínuo)')
701
810
  .option('--client-id <id>', 'oauthClientId do workspace')
702
811
  .option('-f, --follow', 'tail contínuo (poll a cada 5s)')
703
812
  .option('-n, --lines <count>', 'número de linhas a buscar', '50')
@@ -722,7 +831,7 @@ program
722
831
  // ── neetru validate ───────────────────────────────────────────────────
723
832
  program
724
833
  .command('validate')
725
- .description('Health check da config local + conexão com Core')
834
+ .description('Validar config local e conexão com o Core')
726
835
  .action(async () => {
727
836
  const { runValidate } = await import('./commands/validate.js');
728
837
  await runValidate();
@@ -730,7 +839,7 @@ program
730
839
  // ── neetru open ───────────────────────────────────────────────────────
731
840
  program
732
841
  .command('open [target]')
733
- .description('Abre uma página do painel Neetru no browser')
842
+ .description('Abrir página do painel Neetru no browser')
734
843
  .option('--client-id <id>', 'oauthClientId do workspace (anexa em targets workspace-scoped)')
735
844
  .action(async (target, opts) => {
736
845
  const { runOpen } = await import('./commands/open.js');
@@ -739,7 +848,7 @@ program
739
848
  // ── neetru publish ────────────────────────────────────────────────────
740
849
  program
741
850
  .command('publish')
742
- .description('Publica o produto no catálogo público da landing (public_products)')
851
+ .description('Publicar produto no catálogo público da landing')
743
852
  .option('--draft', 'salva como rascunho (published=false)')
744
853
  .option('--unpublish', 'remove o produto da landing (mantém o doc)')
745
854
  .option('--slug <slug>', 'override do slug do neetru.config.json')
@@ -770,7 +879,7 @@ program
770
879
  // ── neetru add ────────────────────────────────────────────────────────
771
880
  program
772
881
  .command('add <feature>')
773
- .description('v1.3 copia template (auth | billing | usage | users | support) pra src/lib/neetru/')
882
+ .description('Adicionar template de feature (auth/billing/usage/...)')
774
883
  .option('--force', 'sobrescrever arquivos existentes')
775
884
  .action(async (feature, opts) => {
776
885
  const { runAdd } = await import('./commands/add.js');
@@ -779,10 +888,10 @@ program
779
888
  // ── neetru mocks ──────────────────────────────────────────────────────
780
889
  const mocksCmd = program
781
890
  .command('mocks')
782
- .description('v1.3 gerenciar fixtures dev (NEETRU_ENV=dev)');
891
+ .description('Gerenciar fixtures de dev (NEETRU_ENV=dev)');
783
892
  mocksCmd
784
893
  .command('reset')
785
- .description('Reseta .neetru/dev-fixtures.json para {}')
894
+ .description('Resetar fixtures de dev para vazio')
786
895
  .action(async () => {
787
896
  const { runMocksReset } = await import('./commands/mocks.js');
788
897
  await runMocksReset();
@@ -790,10 +899,10 @@ mocksCmd
790
899
  // ── neetru env ────────────────────────────────────────────────────────
791
900
  const envCmd = program
792
901
  .command('env')
793
- .description('v1.3 — gerenciar configuração NEETRU_ENV no .env.local');
902
+ .description('Gerenciar NEETRU_ENV no .env.local');
794
903
  envCmd
795
904
  .command('switch <target>')
796
- .description('Alterna NEETRU_ENV: dev | workspace | production')
905
+ .description('Alternar NEETRU_ENV (dev/workspace/production)')
797
906
  .action(async (target) => {
798
907
  const { runEnvSwitch } = await import('./commands/env.js');
799
908
  await runEnvSwitch({ target });
@@ -801,10 +910,10 @@ envCmd
801
910
  // ── neetru db ─────────────────────────────────────────────────────────
802
911
  const dbCmd = program
803
912
  .command('db')
804
- .description('v1.4 gerência de schema/migrations/seed do produto');
913
+ .description('Gerenciar schema, migrations e seed do produto');
805
914
  dbCmd
806
915
  .command('init')
807
- .description('Cria manifest stub a partir de neetru.config.json')
916
+ .description('Criar manifest de schema a partir do config')
808
917
  .option('--out <path>', 'caminho do manifest (default db/schema.manifest.json)')
809
918
  .option('--force', 'sobrescreve se já existir')
810
919
  .action(async (opts) => {
@@ -813,7 +922,7 @@ dbCmd
813
922
  });
814
923
  dbCmd
815
924
  .command('migrate <toVersion>')
816
- .description('Aplica migration via Core (chama runMigrations Sprint 8)')
925
+ .description('Aplicar migration de schema via Core')
817
926
  .option('--from <fromVersion>', 'versão atual (default: schemaVersion do config)')
818
927
  .action(async (toVersion, opts) => {
819
928
  const { runDbMigrate } = await import('./commands/db.js');
@@ -821,7 +930,7 @@ dbCmd
821
930
  });
822
931
  dbCmd
823
932
  .command('seed')
824
- .description('Executa db/seed.ts no projeto (NEETRU_ENV=dev)')
933
+ .description('Executar script de seed do produto')
825
934
  .option('--script <path>', 'caminho custom do script de seed')
826
935
  .action(async (opts) => {
827
936
  const { runDbSeed } = await import('./commands/db.js');
@@ -830,10 +939,10 @@ dbCmd
830
939
  // ── neetru fn ─────────────────────────────────────────────────────────
831
940
  const fnCmd = program
832
941
  .command('fn')
833
- .description('v1.4 gestão de Functions/APIs do produto');
942
+ .description('Gerenciar Functions e APIs do produto');
834
943
  fnCmd
835
944
  .command('deploy')
836
- .description('Registra nova versão da API no catálogo neetru-apis (Sprint 7 stub)')
945
+ .description('Registrar nova versão da API no catálogo')
837
946
  .option('--version <v>', 'versão da API (default: apiVersion do config ou v1)')
838
947
  .option('--channel <channel>', 'stable | beta | alpha', 'stable')
839
948
  .option('--spec <path>', 'caminho de OpenAPI/JSON schema')
@@ -844,7 +953,7 @@ fnCmd
844
953
  // ── neetru promote ────────────────────────────────────────────────────
845
954
  program
846
955
  .command('promote')
847
- .description('v1.4 — solicita promotion entre ambientes (staff-gated). dev→workspace→beta→prod')
956
+ .description('Solicitar promotion entre ambientes (staff-gated)')
848
957
  .requiredOption('--from <env>', 'dev | workspace | beta | prod')
849
958
  .requiredOption('--to <env>', 'dev | workspace | beta | prod')
850
959
  .option('--product <slug>', 'override do slug do neetru.config.json')
@@ -865,7 +974,7 @@ program
865
974
  // ── neetru doctor ─────────────────────────────────────────────────────
866
975
  program
867
976
  .command('doctor')
868
- .description('v2.0 diagnóstico do CLI: token, core, schema, NEETRU_ENV, version')
977
+ .description('Diagnosticar saúde do CLI (token, core, schema, env)')
869
978
  .option('--json', 'saída em JSON (machine-readable)')
870
979
  .action(async (opts) => {
871
980
  const { runDoctor } = await import('./commands/doctor.js');
@@ -874,7 +983,7 @@ program
874
983
  // ── neetru upgrade ────────────────────────────────────────────────────
875
984
  program
876
985
  .command('upgrade')
877
- .description('v2.0 verifica latest no npm e exibe instrução de upgrade')
986
+ .description('Verificar versão mais recente do CLI no npm')
878
987
  .option('--json', 'saída em JSON')
879
988
  .action(async (opts) => {
880
989
  const { runUpgrade } = await import('./commands/upgrade.js');
@@ -883,7 +992,7 @@ program
883
992
  // ── neetru autocomplete ───────────────────────────────────────────────
884
993
  program
885
994
  .command('autocomplete <shell>')
886
- .description('v2.0 — gera script de shell completion (bash | zsh | pwsh)')
995
+ .description('Gerar script de shell completion (bash/zsh/pwsh)')
887
996
  .action(async (shell) => {
888
997
  const { runAutocomplete } = await import('./commands/autocomplete.js');
889
998
  await runAutocomplete(shell);
@@ -891,10 +1000,10 @@ program
891
1000
  // ── neetru agent release ──────────────────────────────────────────────
892
1001
  const agentCmd = program
893
1002
  .command('agent')
894
- .description('Operações sobre o binário do Neetru Agent (Linux daemon)');
1003
+ .description('Gerenciar binário do Neetru Agent (Linux daemon)');
895
1004
  agentCmd
896
1005
  .command('release')
897
- .description('Registra nova release do agente em agent_releases (Firestore)')
1006
+ .description('Registrar nova release do agente em agent_releases')
898
1007
  .requiredOption('--version <semver>', 'versão (ex: 1.2.0 ou 1.2.0-beta.1)')
899
1008
  .option('--channel <channel>', 'stable | beta | canary (default: beta)', 'beta')
900
1009
  .option('--changelog <text|@file>', 'changelog markdown inline ou "@path" pra ler de arquivo')
@@ -916,7 +1025,7 @@ agentCmd
916
1025
  });
917
1026
  agentCmd
918
1027
  .command('yank <version>')
919
- .description('Soft-revoke de uma release do agente (destrutivo top-tier confirmação + step-up MFA)')
1028
+ .description('Revogar release do agente (destrutivo — exige MFA)')
920
1029
  .requiredOption('--reason <text>', 'motivo do yank (mínimo 5 caracteres)')
921
1030
  .option('--yes', 'pula a confirmação interativa (modo script)')
922
1031
  .option('--force', 'alias de --yes')
@@ -936,10 +1045,10 @@ agentCmd
936
1045
  });
937
1046
  const agentCanaryCmd = agentCmd
938
1047
  .command('canary')
939
- .description('Controla o canary rollout de releases do agente');
1048
+ .description('Controlar canary rollout de releases do agente');
940
1049
  agentCanaryCmd
941
1050
  .command('start <version>')
942
- .description('Inicia o canary rollout de uma release (phase1 = 5%)')
1051
+ .description('Iniciar canary rollout de uma release (phase1 5%)')
943
1052
  .option('--json', 'saída em JSON')
944
1053
  .action(async (version, opts) => {
945
1054
  const { runAgentCanaryStart } = await import('./commands/agent-write.js');
@@ -947,7 +1056,7 @@ agentCanaryCmd
947
1056
  });
948
1057
  agentCanaryCmd
949
1058
  .command('rollback <version>')
950
- .description('Rollback do canary de uma release (destrutivo top-tier confirmação + step-up MFA)')
1059
+ .description('Reverter canary de uma release (destrutivo — exige MFA)')
951
1060
  .requiredOption('--reason <text>', 'motivo do rollback (mínimo 5 caracteres)')
952
1061
  .option('--yes', 'pula a confirmação interativa (modo script)')
953
1062
  .option('--force', 'alias de --yes')
@@ -968,13 +1077,13 @@ agentCanaryCmd
968
1077
  // ── neetru support ───────────────────────────────────────────────────
969
1078
  const supportCmd = program
970
1079
  .command('support')
971
- .description('Support tickets inbox staff via CLI (F5 §4.2.6)');
1080
+ .description('Gerenciar suporte ao cliente via CLI');
972
1081
  const supportTicketsCmd = supportCmd
973
1082
  .command('tickets')
974
- .description('Operações sobre support_tickets');
1083
+ .description('Operar tickets de suporte');
975
1084
  supportTicketsCmd
976
1085
  .command('list')
977
- .description('Lista tickets com filtros')
1086
+ .description('Listar tickets de suporte')
978
1087
  .option('--status <s>', 'open | in_progress | resolved | closed')
979
1088
  .option('--severity <s>', 'sev1 | sev2 | sev3 | sev4')
980
1089
  .option('--product <id>', 'filtra por productId')
@@ -996,7 +1105,7 @@ supportTicketsCmd
996
1105
  });
997
1106
  supportTicketsCmd
998
1107
  .command('describe <id>')
999
- .description('Detalha um ticket + thread de mensagens')
1108
+ .description('Mostrar ticket com thread de mensagens')
1000
1109
  .option('--json', 'saída em JSON')
1001
1110
  .action(async (id, opts) => {
1002
1111
  const { runSupportTicketsDescribe } = await import('./commands/support.js');
@@ -1004,7 +1113,7 @@ supportTicketsCmd
1004
1113
  });
1005
1114
  supportTicketsCmd
1006
1115
  .command('reply <id>')
1007
- .description('Anexa mensagem staff ao ticket (transiciona open → in_progress se aplicável)')
1116
+ .description('Responder ticket com mensagem staff')
1008
1117
  .requiredOption('--message <text>', 'corpo da mensagem')
1009
1118
  .option('--json', 'saída em JSON')
1010
1119
  .action(async (id, opts) => {
@@ -1013,7 +1122,7 @@ supportTicketsCmd
1013
1122
  });
1014
1123
  supportTicketsCmd
1015
1124
  .command('assign <id>')
1016
- .description('Atribui ticket a um staff (uid)')
1125
+ .description('Atribuir ticket a um staff')
1017
1126
  .requiredOption('--to <staffUid>', 'uid do staff destino')
1018
1127
  .option('--json', 'saída em JSON')
1019
1128
  .action(async (id, opts) => {
@@ -1022,7 +1131,7 @@ supportTicketsCmd
1022
1131
  });
1023
1132
  supportTicketsCmd
1024
1133
  .command('status <id>')
1025
- .description('Transiciona status do ticket (FSM)')
1134
+ .description('Transicionar status do ticket')
1026
1135
  .requiredOption('--to <status>', 'open | in_progress | resolved | closed')
1027
1136
  .option('--json', 'saída em JSON')
1028
1137
  .action(async (id, opts) => {
@@ -1030,12 +1139,12 @@ supportTicketsCmd
1030
1139
  await runSupportTicketsStatus(id, { to: opts.to, json: !!opts.json });
1031
1140
  });
1032
1141
  // ── neetru dns ───────────────────────────────────────────────────────
1033
- const dnsCmd = program.command('dns').description('Cloud DNS managed zones');
1142
+ const dnsCmd = program.command('dns').description('Gerenciar Cloud DNS managed zones');
1034
1143
  dnsCmd
1035
1144
  .command('zones')
1036
- .description('Operações sobre managed zones')
1145
+ .description('Operar managed zones do Cloud DNS')
1037
1146
  .command('list')
1038
- .description('Lista managed zones do projeto')
1147
+ .description('Listar managed zones do projeto')
1039
1148
  .option('--json', 'saída em JSON')
1040
1149
  .action(async (opts) => {
1041
1150
  const { runDnsZonesList } = await import('./commands/infra-read.js');
@@ -1044,9 +1153,9 @@ dnsCmd
1044
1153
  // ── neetru hosting ───────────────────────────────────────────────────
1045
1154
  program
1046
1155
  .command('hosting')
1047
- .description('Customer domains hosting setup')
1156
+ .description('Gerenciar customer domains e hosting setup')
1048
1157
  .command('list')
1049
- .description('Lista customer domains com scope de tenant aplicado')
1158
+ .description('Listar customer domains com scope de tenant')
1050
1159
  .option('--json', 'saída em JSON')
1051
1160
  .action(async (opts) => {
1052
1161
  const { runHostingList } = await import('./commands/infra-read.js');
@@ -1055,9 +1164,9 @@ program
1055
1164
  // ── neetru builds ────────────────────────────────────────────────────
1056
1165
  program
1057
1166
  .command('builds')
1058
- .description('Cloud Build — builds live (status + duração)')
1167
+ .description('Consultar Cloud Build (status e duração)')
1059
1168
  .command('list')
1060
- .description('Lista Cloud Builds recentes (global + regional)')
1169
+ .description('Listar Cloud Builds recentes (global e regional)')
1061
1170
  .option('--json', 'saída em JSON')
1062
1171
  .action(async (opts) => {
1063
1172
  const { runBuildsList } = await import('./commands/infra-read.js');
@@ -1067,13 +1176,13 @@ program
1067
1176
  // Disaster Recovery — listar exports + restore assistido (admin + step-up MFA).
1068
1177
  const drCmd = program
1069
1178
  .command('dr')
1070
- .description('Disaster Recovery — exports + restore (admin only, RUNBOOK_DR_DRILL)');
1179
+ .description('Operar Disaster Recovery (admin only)');
1071
1180
  const drExportsCmd = drCmd
1072
1181
  .command('exports')
1073
- .description('Operações sobre exports de Firestore em gs://neetru-backups');
1182
+ .description('Operar exports de Firestore em gs://neetru-backups');
1074
1183
  drExportsCmd
1075
1184
  .command('list')
1076
- .description('Lista exports disponíveis (sort: mais recente primeiro)')
1185
+ .description('Listar exports de DR disponíveis')
1077
1186
  .option('--json', 'saída em JSON')
1078
1187
  .action(async (opts) => {
1079
1188
  const { runDrExportsList } = await import('./commands/dr.js');
@@ -1081,7 +1190,7 @@ drExportsCmd
1081
1190
  });
1082
1191
  drCmd
1083
1192
  .command('restore')
1084
- .description('Dispara restore Firestore (IRREVERSÍVEL no destino destrutivo top-tier)')
1193
+ .description('Restaurar Firestore de export (IRREVERSÍVEL — exige MFA)')
1085
1194
  .requiredOption('--gcs-path <path>', 'gs://neetru-backups/firestore-exports/<stamp>/')
1086
1195
  .requiredOption('--target-project <project>', 'projeto GCP de destino (deve ser STAGING)')
1087
1196
  .option('--yes', 'pula a confirmação interativa (modo script)')