@neetru/cli 2.2.0 → 2.4.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.
Files changed (48) hide show
  1. package/dist/commands/ai.js +82 -10
  2. package/dist/commands/ai.js.map +1 -1
  3. package/dist/commands/auth.d.ts +19 -0
  4. package/dist/commands/auth.js +203 -0
  5. package/dist/commands/auth.js.map +1 -0
  6. package/dist/commands/deploy.js +8 -8
  7. package/dist/commands/deployments.d.ts +5 -5
  8. package/dist/commands/deployments.js +32 -6
  9. package/dist/commands/deployments.js.map +1 -1
  10. package/dist/commands/products-db.d.ts +9 -9
  11. package/dist/commands/products-db.js +84 -19
  12. package/dist/commands/products-db.js.map +1 -1
  13. package/dist/commands/products.d.ts +2 -2
  14. package/dist/commands/products.js +8 -6
  15. package/dist/commands/products.js.map +1 -1
  16. package/dist/commands/schema.d.ts +25 -0
  17. package/dist/commands/schema.js +321 -0
  18. package/dist/commands/schema.js.map +1 -0
  19. package/dist/commands/servers.d.ts +5 -5
  20. package/dist/commands/servers.js +25 -17
  21. package/dist/commands/servers.js.map +1 -1
  22. package/dist/commands/status.js +3 -2
  23. package/dist/commands/status.js.map +1 -1
  24. package/dist/commands/tenants.d.ts +14 -14
  25. package/dist/commands/tenants.js +62 -30
  26. package/dist/commands/tenants.js.map +1 -1
  27. package/dist/commands/ui.d.ts +1 -0
  28. package/dist/commands/ui.js +454 -0
  29. package/dist/commands/ui.js.map +1 -0
  30. package/dist/commands/workspaces.d.ts +9 -9
  31. package/dist/commands/workspaces.js +66 -31
  32. package/dist/commands/workspaces.js.map +1 -1
  33. package/dist/index.js +226 -165
  34. package/dist/index.js.map +1 -1
  35. package/dist/lib/ai/auth-discovery.d.ts +26 -0
  36. package/dist/lib/ai/auth-discovery.js +256 -0
  37. package/dist/lib/ai/auth-discovery.js.map +1 -0
  38. package/dist/lib/ai/orchestrator.d.ts +25 -0
  39. package/dist/lib/ai/orchestrator.js +190 -28
  40. package/dist/lib/ai/orchestrator.js.map +1 -1
  41. package/dist/lib/config-schema.d.ts +18 -18
  42. package/dist/lib/pickers.d.ts +123 -0
  43. package/dist/lib/pickers.js +336 -0
  44. package/dist/lib/pickers.js.map +1 -0
  45. package/dist/lib/schema-cache.d.ts +87 -0
  46. package/dist/lib/schema-cache.js +134 -0
  47. package/dist/lib/schema-cache.js.map +1 -0
  48. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5,22 +5,30 @@ import { CLI_VERSION } from './version.js';
5
5
  const program = new Command();
6
6
  program
7
7
  .name('neetru')
8
- .description('Neetru Developer Kit scaffold, AI assistant e deploy para produtos SaaS')
8
+ .description('Operar o Neetru Developer Kit (scaffold, AI, deploy)')
9
9
  .version(CLI_VERSION);
10
10
  // ── neetru ai ─────────────────────────────────────────────────────────
11
11
  program
12
12
  .command('ai')
13
- .description('REPL interativo com IA Neetru-aware (Claude / OpenAI / Gemini)')
13
+ .description('Abrir REPL de IA Neetru-aware (Claude/OpenAI/Gemini)')
14
14
  .option('-m, --model <model>', 'modelo: claude | openai | gemini | auto', 'auto')
15
15
  .action(async (opts) => {
16
16
  const { runAiRepl } = await import('./commands/ai.js');
17
17
  await runAiRepl({ model: opts.model });
18
18
  });
19
+ program
20
+ .command('ui')
21
+ .alias('menu')
22
+ .description('Abrir a interface interativa do Neetru CLI')
23
+ .action(async () => {
24
+ const { runTerminalUi } = await import('./commands/ui.js');
25
+ await runTerminalUi();
26
+ });
19
27
  // ── neetru init ───────────────────────────────────────────────────────
20
28
  // v2.1.1 — prompt interativo de caminho + merge mode + preserva arquivos
21
29
  program
22
30
  .command('init <name>')
23
- .description('Scaffold de novo produto SaaS Neetru (interativo — escolhe new subdir | merge cwd | custom path)')
31
+ .description('Inicializar scaffold de produto SaaS Neetru')
24
32
  .option('--type <type>', 'nextjs | node-api', 'nextjs')
25
33
  .option('--here', 'init no cwd atual (modo merge — preserva existentes)')
26
34
  .option('--path <path>', 'custom path target')
@@ -41,7 +49,7 @@ program
41
49
  // Cria produto + workspace + scaffold local + abre painel — single command.
42
50
  program
43
51
  .command('new <name>')
44
- .description('Macro: cria produto + workspace + scaffold + abre painel (end-to-end)')
52
+ .description('Criar produto, workspace, scaffold e abrir painel')
45
53
  .option('--product-slug <slug>', 'slug do produto (default: derivado de <name>)')
46
54
  .option('--env <env>', 'dev (default) | staging | prod', 'dev')
47
55
  .option('--tier <tier>', 'standard (default) | dev | enterprise', 'standard')
@@ -61,27 +69,56 @@ program
61
69
  json: !!opts.json,
62
70
  });
63
71
  });
72
+ // ── neetru auth ───────────────────────────────────────────────────────
73
+ // Wave D — detecta Claude Code/Codex/Gemini instalados e reaproveita creds.
74
+ const authCmd = program
75
+ .command('auth')
76
+ .description('Gerenciar credenciais de IA (Claude, Codex, Gemini)');
77
+ authCmd
78
+ .command('status')
79
+ .description('Listar provedores detectados e estado das credenciais')
80
+ .option('--json', 'saída JSON')
81
+ .action(async (opts) => {
82
+ const { runAuthStatus } = await import('./commands/auth.js');
83
+ await runAuthStatus({ json: !!opts.json });
84
+ });
85
+ authCmd
86
+ .command('setup')
87
+ .description('Wizard interativo: detectar, instalar, configurar')
88
+ .option('--json', 'modo não-interativo (equivalente a pull)')
89
+ .action(async (opts) => {
90
+ const { runAuthSetup } = await import('./commands/auth.js');
91
+ await runAuthSetup({ json: !!opts.json });
92
+ });
93
+ authCmd
94
+ .command('pull')
95
+ .description('Copiar creds dos CLIs detectados pra config do Neetru')
96
+ .option('--json', 'saída JSON')
97
+ .action(async (opts) => {
98
+ const { runAuthPull } = await import('./commands/auth.js');
99
+ await runAuthPull({ json: !!opts.json });
100
+ });
64
101
  // ── neetru config ─────────────────────────────────────────────────────
65
102
  const configCmd = program
66
103
  .command('config')
67
- .description('Gerenciar configurações do CLI (chaves de API, modelo padrão)');
104
+ .description('Gerenciar configurações do CLI');
68
105
  configCmd
69
106
  .command('set <key> <value>')
70
- .description('Define uma configuração')
107
+ .description('Definir valor de configuração')
71
108
  .action(async (key, value) => {
72
109
  const { configSet } = await import('./commands/config.js');
73
110
  configSet(key, value);
74
111
  });
75
112
  configCmd
76
113
  .command('get [key]')
77
- .description(' configuração(ões)')
114
+ .description('Ler configuração por chave (ou todas)')
78
115
  .action(async (key) => {
79
116
  const { configGet } = await import('./commands/config.js');
80
117
  configGet(key);
81
118
  });
82
119
  configCmd
83
120
  .command('path')
84
- .description('Mostra o caminho do arquivo de configuração')
121
+ .description('Mostrar caminho do arquivo de configuração')
85
122
  .action(async () => {
86
123
  const { configPath } = await import('./commands/config.js');
87
124
  configPath();
@@ -89,7 +126,7 @@ configCmd
89
126
  // ── neetru login ──────────────────────────────────────────────────────
90
127
  program
91
128
  .command('login')
92
- .description('Autentica o CLI via Device Code OAuth (RFC 8628)')
129
+ .description('Autenticar CLI via Device Code OAuth (RFC 8628)')
93
130
  .option('--token <token>', 'token nrt_<keyId>_<secret> (modo CI/legado, pula browser)')
94
131
  .option('--json', 'saída em JSON (machine-readable)')
95
132
  .action(async (opts) => {
@@ -99,7 +136,7 @@ program
99
136
  // ── neetru logout ─────────────────────────────────────────────────────
100
137
  program
101
138
  .command('logout')
102
- .description('Apaga as credenciais locais (~/.config/neetru-cli/auth.json + cache legado)')
139
+ .description('Remover credenciais locais do CLI')
103
140
  .action(async () => {
104
141
  const { runLogout } = await import('./commands/logout.js');
105
142
  await runLogout();
@@ -107,7 +144,7 @@ program
107
144
  // ── neetru whoami ─────────────────────────────────────────────────────
108
145
  program
109
146
  .command('whoami')
110
- .description('Mostra a identidade da chave CLI corrente')
147
+ .description('Mostrar identidade da chave CLI corrente')
111
148
  .option('--json', 'saída em JSON')
112
149
  .action(async (opts) => {
113
150
  const { runWhoami } = await import('./commands/whoami.js');
@@ -116,7 +153,7 @@ program
116
153
  // ── neetru build ──────────────────────────────────────────────────────
117
154
  program
118
155
  .command('build')
119
- .description('Empacota o produto no diretório atual num tarball pronto para deploy')
156
+ .description('Construir tarball do produto pronto para deploy')
120
157
  .option('--product <slug>', 'override do slug (default: lê neetru.config.json)')
121
158
  .option('--stack <stack>', 'node | docker | php-apache | static (default: detectado)')
122
159
  .option('--output <dir>', 'diretório de saída', '.neetru-build')
@@ -135,7 +172,7 @@ program
135
172
  // ── neetru deploy ─────────────────────────────────────────────────────
136
173
  program
137
174
  .command('deploy')
138
- .description('Deploy do produto via pipeline Neetru Core (interativo por default)')
175
+ .description('Deployar produto via pipeline do Neetru Core')
139
176
  .option('--product <slug>', 'slug do produto')
140
177
  .option('--version <version>', 'versão a deployar')
141
178
  .option('--stack <stack>', 'node | docker | php-apache | static')
@@ -174,7 +211,7 @@ program
174
211
  // delega ao status de workspace legado (backward-compat).
175
212
  program
176
213
  .command('status')
177
- .description('Saúde das superfícies públicas (landing/api/portal/políticas). --client-id = status de workspace')
214
+ .description('Verificar saúde das superfícies públicas do Core')
178
215
  .option('--client-id <id>', 'oauthClientId do workspace (status de workspace legado)')
179
216
  .option('--json', 'saída em JSON')
180
217
  .action(async (opts) => {
@@ -184,10 +221,10 @@ program
184
221
  // ── neetru tenants ────────────────────────────────────────────────────
185
222
  const tenantsCmd = program
186
223
  .command('tenants')
187
- .description('Control plane — inspeção de tenants (read-only)');
224
+ .description('Gerenciar tenants (read-only)');
188
225
  tenantsCmd
189
226
  .command('list')
190
- .description('Lista tenants (filtros --status / --product)')
227
+ .description('Listar tenants')
191
228
  .option('--status <status>', 'ativo | em provisionamento | suspenso | arquivado')
192
229
  .option('--product <productId>', 'filtra por productId')
193
230
  .option('--limit <n>', 'máximo de resultados (default 100, max 500)')
@@ -202,8 +239,8 @@ tenantsCmd
202
239
  });
203
240
  });
204
241
  tenantsCmd
205
- .command('get <id>')
206
- .description('Detalha um tenant pelo ID')
242
+ .command('get [id]')
243
+ .description('Mostrar detalhes de um tenant')
207
244
  .option('--json', 'saída em JSON')
208
245
  .action(async (id, opts) => {
209
246
  const { runTenantsGet } = await import('./commands/tenants.js');
@@ -211,12 +248,12 @@ tenantsCmd
211
248
  });
212
249
  tenantsCmd
213
250
  .command('create')
214
- .description('Cria um tenant (status inicial: em provisionamento)')
215
- .requiredOption('--name <name>', 'nome do tenant')
216
- .requiredOption('--slug <slug>', 'slug do tenant')
217
- .requiredOption('--customer <customerId>', 'id do customer')
218
- .requiredOption('--product <productId>', 'id do produto')
219
- .requiredOption('--env <env>', 'dev | staging | prod')
251
+ .description('Criar tenant (status inicial: em provisionamento)')
252
+ .option('--name <name>', 'nome do tenant')
253
+ .option('--slug <slug>', 'slug do tenant')
254
+ .option('--customer <customerId>', 'id do customer')
255
+ .option('--product <productId>', 'id do produto (interativo se ausente)')
256
+ .option('--env <env>', 'dev | staging | prod (default: dev)')
220
257
  .option('--domain <domain>', 'domínio primário')
221
258
  .option('--json', 'saída em JSON')
222
259
  .action(async (opts) => {
@@ -232,13 +269,13 @@ tenantsCmd
232
269
  });
233
270
  });
234
271
  tenantsCmd
235
- .command('update <id>')
236
- .description('Atualiza dados de um tenant existente')
237
- .requiredOption('--name <name>', 'nome do tenant')
238
- .requiredOption('--slug <slug>', 'slug do tenant')
239
- .requiredOption('--customer <customerId>', 'id do customer')
240
- .requiredOption('--product <productId>', 'id do produto')
241
- .requiredOption('--env <env>', 'dev | staging | prod')
272
+ .command('update [id]')
273
+ .description('Atualizar dados de um tenant')
274
+ .option('--name <name>', 'nome do tenant')
275
+ .option('--slug <slug>', 'slug do tenant')
276
+ .option('--customer <customerId>', 'id do customer')
277
+ .option('--product <productId>', 'id do produto (interativo se ausente)')
278
+ .option('--env <env>', 'dev | staging | prod (default: dev)')
242
279
  .option('--domain <domain>', 'domínio primário')
243
280
  .option('--json', 'saída em JSON')
244
281
  .action(async (id, opts) => {
@@ -254,8 +291,8 @@ tenantsCmd
254
291
  });
255
292
  });
256
293
  tenantsCmd
257
- .command('suspend <id>')
258
- .description('Suspende um tenant (destrutivo — confirmação interativa)')
294
+ .command('suspend [id]')
295
+ .description('Suspender tenant (destrutivo — exige confirmação)')
259
296
  .option('--yes', 'pula a confirmação interativa (modo script)')
260
297
  .option('--force', 'alias de --yes')
261
298
  .option('--json', 'saída em JSON')
@@ -264,8 +301,8 @@ tenantsCmd
264
301
  await runTenantsSuspend(id, { yes: !!opts.yes, force: !!opts.force, json: !!opts.json });
265
302
  });
266
303
  tenantsCmd
267
- .command('reactivate <id>')
268
- .description('Reativa um tenant suspenso')
304
+ .command('reactivate [id]')
305
+ .description('Reativar tenant suspenso')
269
306
  .option('--json', 'saída em JSON')
270
307
  .action(async (id, opts) => {
271
308
  const { runTenantsReactivate } = await import('./commands/tenants.js');
@@ -274,10 +311,10 @@ tenantsCmd
274
311
  // ── neetru audit ──────────────────────────────────────────────────────
275
312
  const auditCmd = program
276
313
  .command('audit')
277
- .description('Control plane — trilha de auditoria do Core (read-only)');
314
+ .description('Consultar trilha de auditoria do Core (read-only)');
278
315
  auditCmd
279
316
  .command('tail')
280
- .description('Últimos N eventos de audit_logs (mais recente primeiro)')
317
+ .description('Listar últimos eventos de audit_logs')
281
318
  .option('-n, --limit <n>', 'número de eventos (default 50, max 200)')
282
319
  .option('--action <substring>', 'filtra por substring da ação (ex: billing, tenant.create)')
283
320
  .option('--severity <level>', 'info | warning | critical')
@@ -296,10 +333,10 @@ auditCmd
296
333
  // ── neetru billing ────────────────────────────────────────────────────
297
334
  const billingCmd = program
298
335
  .command('billing')
299
- .description('Control plane billing/contabilidade (read-only)');
336
+ .description('Consultar billing e contabilidade (read-only)');
300
337
  billingCmd
301
338
  .command('summary')
302
- .description('Sumário contábil do mês corrente (MRR, invoices, subscriptions)')
339
+ .description('Mostrar sumário contábil do mês (MRR, invoices, subs)')
303
340
  .option('--year <YYYY>', 'ano (default: corrente)')
304
341
  .option('--month <1-12>', 'mês (default: corrente)')
305
342
  .option('--json', 'saída em JSON')
@@ -310,18 +347,24 @@ billingCmd
310
347
  // ── neetru servers ────────────────────────────────────────────────────
311
348
  const serversCmd = program
312
349
  .command('servers')
313
- .description('Control plane inventário de servers (read-only)');
350
+ .description('Gerenciar servers e inventário de VMs');
314
351
  serversCmd
315
352
  .command('list')
316
- .description('Lista servers (filtros --status / --provider / --capacity)')
317
- .option('--status <status>', 'online (operacional + heartbeat fresco)')
353
+ .description('Listar servers')
354
+ .option('--status <status>', 'online | operacional (ativo) ou offline | desconectado (inativo)')
318
355
  .option('--provider <provider>', 'hetzner | digitalocean | aws | ...')
319
356
  .option('--capacity', 'inclui colunas de RAM/CPU/disco')
320
357
  .option('--json', 'saída em JSON')
321
358
  .action(async (opts) => {
359
+ const STATUS_ALIASES = {
360
+ operacional: 'online',
361
+ desconectado: 'offline',
362
+ };
363
+ const rawStatus = opts.status;
364
+ const resolvedStatus = rawStatus ? (STATUS_ALIASES[rawStatus] ?? rawStatus) : undefined;
322
365
  const { runServersList } = await import('./commands/servers.js');
323
366
  await runServersList({
324
- status: opts.status,
367
+ status: resolvedStatus,
325
368
  provider: opts.provider,
326
369
  capacity: !!opts.capacity,
327
370
  json: !!opts.json,
@@ -329,10 +372,10 @@ serversCmd
329
372
  });
330
373
  serversCmd
331
374
  .command('provision')
332
- .description('Provisiona uma VM GCP (admin only) — cria server + registration token')
333
- .requiredOption('--name <name>', 'nome do servidor')
334
- .requiredOption('--zone <zone>', 'zona GCP (ex: us-central1-a)')
335
- .requiredOption('--machine-type <type>', 'machine type GCP (ex: e2-small)')
375
+ .description('Provisionar VM GCP e gerar registration token (admin)')
376
+ .option('--name <name>', 'nome do servidor')
377
+ .option('--zone <zone>', 'zona GCP (ex: us-central1-a)')
378
+ .option('--machine-type <type>', 'machine type GCP (ex: e2-small)')
336
379
  .option('--tenant <tenantId>', 'tenant associado')
337
380
  .option('--customer <customerId>', 'customer associado')
338
381
  .option('--json', 'saída em JSON')
@@ -348,8 +391,8 @@ serversCmd
348
391
  });
349
392
  });
350
393
  serversCmd
351
- .command('deactivate <serverId>')
352
- .description('Desativa um server (destrutivo top-tier — confirmação + step-up MFA)')
394
+ .command('deactivate [serverId]')
395
+ .description('Desativar server (destrutivo top-tier — exige MFA)')
353
396
  .option('--yes', 'pula a confirmação interativa (modo script)')
354
397
  .option('--force', 'alias de --yes')
355
398
  .option('--dry-run', 'valida e mostra o efeito sem aplicar')
@@ -366,8 +409,8 @@ serversCmd
366
409
  });
367
410
  });
368
411
  serversCmd
369
- .command('dispatch <serverId> <commandType>')
370
- .description('Enfileira um comando pro agente Linux do server')
412
+ .command('dispatch [serverId] [commandType]')
413
+ .description('Enfileirar comando para o agente Linux do server')
371
414
  .option('--params <json>', 'objeto JSON de params do comando')
372
415
  .option('--json', 'saída em JSON')
373
416
  .action(async (id, commandType, opts) => {
@@ -377,14 +420,14 @@ serversCmd
377
420
  // ── neetru workspaces ─────────────────────────────────────────────────
378
421
  const workspacesCmd = program
379
422
  .command('workspaces')
380
- .description('Control plane — runtime shared de workspaces');
423
+ .description('Gerenciar workspaces compartilhados');
381
424
  workspacesCmd
382
425
  .command('create')
383
- .description('Cria um workspace (devolve OAuth client secret one-time)')
384
- .requiredOption('--product <productId>', 'id do produto')
385
- .requiredOption('--customer <customerId>', 'id do customer')
386
- .requiredOption('--env <env>', 'dev | staging | prod')
387
- .requiredOption('--tier <tier>', 'dev | standard | enterprise')
426
+ .description('Criar workspace (retorna OAuth secret one-time)')
427
+ .option('--product <productId>', 'id do produto (interativo se ausente)')
428
+ .option('--customer <customerId>', 'id do customer (default: self/Neetru)')
429
+ .option('--env <env>', 'dev | staging | prod (default: dev)')
430
+ .option('--tier <tier>', 'dev | standard | enterprise (default: standard)')
388
431
  .option('--name <name>', 'label do workspace')
389
432
  .option('--json', 'saída em JSON')
390
433
  .action(async (opts) => {
@@ -399,10 +442,10 @@ workspacesCmd
399
442
  });
400
443
  });
401
444
  workspacesCmd
402
- .command('advance <workspaceId>')
403
- .description('Promove uma versão de bundle pra "running" no workspace')
404
- .requiredOption('--product <slug>', 'productSlug do bundle')
405
- .requiredOption('--version <version>', 'versão do bundle a ativar')
445
+ .command('advance [workspaceId]')
446
+ .description('Promover versão de bundle para running no workspace')
447
+ .option('--product <slug>', 'productSlug do bundle (interativo se ausente)')
448
+ .option('--version <version>', 'versão do bundle a ativar')
406
449
  .option('--json', 'saída em JSON')
407
450
  .action(async (id, opts) => {
408
451
  const { runWorkspacesAdvance } = await import('./commands/workspaces.js');
@@ -414,7 +457,7 @@ workspacesCmd
414
457
  });
415
458
  workspacesCmd
416
459
  .command('list')
417
- .description('Lista workspaces (filtros --product / --env / --status)')
460
+ .description('Listar workspaces')
418
461
  .option('--product <productId>', 'filtra por productId')
419
462
  .option('--env <env>', 'dev | staging | prod')
420
463
  .option('--status <status>', 'active | paused | provisioning | …')
@@ -429,16 +472,16 @@ workspacesCmd
429
472
  });
430
473
  });
431
474
  workspacesCmd
432
- .command('get <workspaceId>')
433
- .description('Detalha um workspace pelo ID')
475
+ .command('get [workspaceId]')
476
+ .description('Mostrar detalhes de um workspace')
434
477
  .option('--json', 'saída em JSON')
435
478
  .action(async (id, opts) => {
436
479
  const { runWorkspacesGet } = await import('./commands/workspaces.js');
437
480
  await runWorkspacesGet(id, { json: !!opts.json });
438
481
  });
439
482
  workspacesCmd
440
- .command('open <workspaceId>')
441
- .description('Abre o painel do workspace no browser (core.neetru.com/workspaces/<id>)')
483
+ .command('open [workspaceId]')
484
+ .description('Abrir painel do workspace no browser')
442
485
  .action(async (id) => {
443
486
  const { runWorkspacesOpen } = await import('./commands/workspaces.js');
444
487
  await runWorkspacesOpen(id);
@@ -446,15 +489,15 @@ workspacesCmd
446
489
  // ── neetru deployments ────────────────────────────────────────────────
447
490
  const deploymentsCmd = program
448
491
  .command('deployments')
449
- .description('Control plane — recurso deployments/ (paridade com a UI)');
492
+ .description('Gerenciar deployments do Core');
450
493
  deploymentsCmd
451
494
  .command('create')
452
- .description('Cria um deployment (dispara comando deploy pro agente)')
453
- .requiredOption('--product <productId>', 'id do produto')
454
- .requiredOption('--tenant <tenantId>', 'id do tenant alvo')
455
- .requiredOption('--version <version>', 'versão a deployar')
456
- .requiredOption('--env <env>', 'dev | staging | prod')
457
- .requiredOption('--server <serverId>', 'id do server alvo')
495
+ .description('Criar deployment (dispara comando para o agente)')
496
+ .option('--product <productId>', 'id do produto (interativo se ausente)')
497
+ .option('--tenant <tenantId>', 'id do tenant alvo (interativo se ausente)')
498
+ .option('--version <version>', 'versao a deployar')
499
+ .option('--env <env>', 'dev | staging | prod (default: dev)')
500
+ .option('--server <serverId>', 'id do server alvo (interativo se ausente)')
458
501
  .option('--json', 'saída em JSON')
459
502
  .action(async (opts) => {
460
503
  const { runDeploymentsCreate } = await import('./commands/deployments.js');
@@ -469,7 +512,7 @@ deploymentsCmd
469
512
  });
470
513
  deploymentsCmd
471
514
  .command('rollback <deploymentId>')
472
- .description('Rollback de um deployment (destrutivo top-tier — confirmação + step-up MFA)')
515
+ .description('Reverter deployment (destrutivo top-tier — exige MFA)')
473
516
  .option('--yes', 'pula a confirmação interativa (modo script)')
474
517
  .option('--force', 'alias de --yes')
475
518
  .option('--dry-run', 'valida e mostra o efeito sem aplicar')
@@ -488,10 +531,10 @@ deploymentsCmd
488
531
  // ── neetru cloud-run ──────────────────────────────────────────────────
489
532
  const cloudRunCmd = program
490
533
  .command('cloud-run')
491
- .description('Control plane — serviços Cloud Run (admin only)');
534
+ .description('Gerenciar serviços Cloud Run (admin)');
492
535
  cloudRunCmd
493
536
  .command('pause <service>')
494
- .description('Pausa um serviço Cloud Run (scale-to-zero)')
537
+ .description('Pausar serviço Cloud Run (scale-to-zero)')
495
538
  .option('--json', 'saída em JSON')
496
539
  .action(async (service, opts) => {
497
540
  const { runCloudRunPause } = await import('./commands/cloud-run.js');
@@ -499,7 +542,7 @@ cloudRunCmd
499
542
  });
500
543
  cloudRunCmd
501
544
  .command('resume <service>')
502
- .description('Retoma um serviço Cloud Run pausado')
545
+ .description('Retomar serviço Cloud Run pausado')
503
546
  .option('--min-instances <n>', 'minInstanceCount')
504
547
  .option('--max-instances <n>', 'maxInstanceCount')
505
548
  .option('--json', 'saída em JSON')
@@ -513,7 +556,7 @@ cloudRunCmd
513
556
  });
514
557
  cloudRunCmd
515
558
  .command('delete <service>')
516
- .description('Exclui um serviço Cloud Run (IRREVERSÍVEL — confirmação + step-up MFA)')
559
+ .description('Remover serviço Cloud Run (IRREVERSÍVEL — exige MFA)')
517
560
  .option('--yes', 'pula a confirmação interativa (modo script)')
518
561
  .option('--force', 'alias de --yes')
519
562
  .option('--dry-run', 'valida e mostra o efeito sem aplicar')
@@ -532,10 +575,10 @@ cloudRunCmd
532
575
  // ── neetru api-catalog ────────────────────────────────────────────────
533
576
  const apiCatalogCmd = program
534
577
  .command('api-catalog')
535
- .description('Control plane — registry de APIs versionadas (apis/)');
578
+ .description('Gerenciar catálogo de APIs versionadas');
536
579
  apiCatalogCmd
537
580
  .command('create <slug>')
538
- .description('Registra uma nova API no catálogo')
581
+ .description('Registrar nova API no catálogo')
539
582
  .requiredOption('--name <name>', 'nome da API')
540
583
  .requiredOption('--base-url <url>', 'base URL')
541
584
  .requiredOption('--version <version>', 'versão')
@@ -565,7 +608,7 @@ apiCatalogCmd
565
608
  });
566
609
  apiCatalogCmd
567
610
  .command('update <slug>')
568
- .description('Atualiza uma entrada do catálogo (slug é imutável)')
611
+ .description('Atualizar entrada do catálogo (slug imutável)')
569
612
  .requiredOption('--name <name>', 'nome da API')
570
613
  .requiredOption('--base-url <url>', 'base URL')
571
614
  .requiredOption('--version <version>', 'versão')
@@ -595,7 +638,7 @@ apiCatalogCmd
595
638
  });
596
639
  apiCatalogCmd
597
640
  .command('archive <slug>')
598
- .description('Soft-delete de uma API (--unarchive reativa)')
641
+ .description('Arquivar API por soft-delete (--unarchive reverte)')
599
642
  .option('--unarchive', 'reativa em vez de arquivar')
600
643
  .option('--yes', 'pula a confirmação interativa (modo script)')
601
644
  .option('--force', 'alias de --yes')
@@ -611,7 +654,7 @@ apiCatalogCmd
611
654
  });
612
655
  apiCatalogCmd
613
656
  .command('delete <slug>')
614
- .description('Delete físico de uma API (IRREVERSÍVEL — confirmação + step-up MFA)')
657
+ .description('Remover API fisicamente (IRREVERSÍVEL — exige MFA)')
615
658
  .option('--yes', 'pula a confirmação interativa (modo script)')
616
659
  .option('--force', 'alias de --yes')
617
660
  .option('--dry-run', 'valida e mostra o efeito sem aplicar')
@@ -630,10 +673,10 @@ apiCatalogCmd
630
673
  // ── neetru products ───────────────────────────────────────────────────
631
674
  const productsCmd = program
632
675
  .command('products')
633
- .description('Control plane — registry interno de produtos SaaS (read-only)');
676
+ .description('Gerenciar registry de produtos SaaS internos');
634
677
  productsCmd
635
678
  .command('list')
636
- .description('Lista produtos internos (registry products/, filtro --status)')
679
+ .description('Listar produtos internos')
637
680
  .option('--status <status>', 'ativo | beta | descontinuado')
638
681
  .option('--limit <n>', 'máximo de resultados (default 100, max 500)')
639
682
  .option('--json', 'saída em JSON')
@@ -643,7 +686,7 @@ productsCmd
643
686
  });
644
687
  productsCmd
645
688
  .command('create')
646
- .description('Cria um produto SaaS interno (interativo por default; --yes pra non-interactive)')
689
+ .description('Criar produto SaaS interno (interativo por default)')
647
690
  .option('--name <name>', 'nome do produto (interativo se ausente)')
648
691
  .option('--slug <slug>', 'slug (auto-derivado de --name se ausente)')
649
692
  .option('--description <text>', 'descrição (opcional)')
@@ -666,16 +709,16 @@ productsCmd
666
709
  });
667
710
  });
668
711
  productsCmd
669
- .command('publish <slug>')
670
- .description('Publica um produto no catálogo público (published=true)')
712
+ .command('publish [slug]')
713
+ .description('Publicar produto no catálogo público')
671
714
  .option('--json', 'saída em JSON')
672
715
  .action(async (slug, opts) => {
673
716
  const { runProductsPublish } = await import('./commands/products.js');
674
717
  await runProductsPublish(slug, { json: !!opts.json });
675
718
  });
676
719
  productsCmd
677
- .command('unpublish <slug>')
678
- .description('Remove um produto do catálogo público (published=false)')
720
+ .command('unpublish [slug]')
721
+ .description('Remover produto do catálogo público')
679
722
  .option('--json', 'saída em JSON')
680
723
  .action(async (slug, opts) => {
681
724
  const { runProductsUnpublish } = await import('./commands/products.js');
@@ -684,14 +727,14 @@ productsCmd
684
727
  // ── neetru products db (Phase A — per-product DB isolation) ────────────
685
728
  const productsDbCmd = productsCmd
686
729
  .command('db')
687
- .description('Bancos de dados isolados por produto (firestore-instance | cloud-sql-* | vm-*)');
730
+ .description('Gerenciar bancos isolados por produto');
688
731
  productsDbCmd
689
732
  .command('list')
690
- .description('Lista bancos. Filtros: --product-id, --engine, --status')
691
- .option('--product-id <id>')
692
- .option('--engine <engine>')
693
- .option('--status <status>')
694
- .option('--json')
733
+ .description('Listar bancos de produtos')
734
+ .option('--product-id <id>', 'ID do produto')
735
+ .option('--engine <engine>', 'firestore-instance | cloud-sql-postgres | cloud-sql-mysql | vm-postgres-single | vm-postgres-cluster | vm-mysql-single | vm-mysql-cluster')
736
+ .option('--status <status>', 'Filtrar por status (ativo, provisionando, falha, arquivado)')
737
+ .option('--json', 'Saída em JSON estruturado')
695
738
  .action(async (opts) => {
696
739
  const { runDbList } = await import('./commands/products-db.js');
697
740
  await runDbList({
@@ -703,7 +746,7 @@ productsDbCmd
703
746
  });
704
747
  productsDbCmd
705
748
  .command('engines')
706
- .description('Lista engines suportados')
749
+ .description('Listar engines de banco suportados')
707
750
  .option('--json')
708
751
  .action(async (opts) => {
709
752
  const { runDbEngines } = await import('./commands/products-db.js');
@@ -711,22 +754,22 @@ productsDbCmd
711
754
  });
712
755
  productsDbCmd
713
756
  .command('create')
714
- .description('Cria um banco (Phase A: registra + audit; provisionamento real é Phase B)')
715
- .requiredOption('--product-id <id>')
716
- .requiredOption('--label <label>')
717
- .requiredOption('--engine <engine>', 'firestore-instance|cloud-sql-postgres|cloud-sql-mysql|vm-postgres-single|vm-postgres-cluster|vm-mysql-single|vm-mysql-cluster')
718
- .requiredOption('--environment <env>', 'dev|staging|production')
719
- .option('--region <region>', 'região GCP', 'us-central1')
720
- .option('--server-id <serverId>', 'target VM (obrigatório pra engines vm-*)')
721
- .option('--replica-count <n>', 'pra engines *-cluster (default 2)')
722
- .option('--json')
757
+ .description('Criar banco de produto (Phase A: registra + audit)')
758
+ .option('--product-id <id>', 'ID do produto')
759
+ .option('--label <label>', 'Nome descritivo do banco')
760
+ .option('--engine <engine>', 'firestore-instance | cloud-sql-postgres | cloud-sql-mysql | vm-postgres-single | vm-postgres-cluster | vm-mysql-single | vm-mysql-cluster')
761
+ .option('--env <env>', 'Ambiente: dev | staging | production')
762
+ .option('--region <region>', 'Região GCP', 'us-central1')
763
+ .option('--server-id <serverId>', 'ID da VM alvo (obrigatório para engines vm-*)')
764
+ .option('--replica-count <n>', 'Número de réplicas para engines *-cluster (padrão 2)')
765
+ .option('--json', 'Saída em JSON estruturado')
723
766
  .action(async (opts) => {
724
767
  const { runDbCreate } = await import('./commands/products-db.js');
725
768
  await runDbCreate({
726
769
  productId: opts.productId,
727
770
  label: opts.label,
728
771
  engine: opts.engine,
729
- environment: opts.environment,
772
+ env: opts.env,
730
773
  region: opts.region,
731
774
  serverId: opts.serverId,
732
775
  replicaCount: opts.replicaCount,
@@ -734,16 +777,16 @@ productsDbCmd
734
777
  });
735
778
  });
736
779
  productsDbCmd
737
- .command('get <id>')
738
- .description('Detalhes de um banco')
780
+ .command('get [id]')
781
+ .description('Mostrar detalhes de um banco')
739
782
  .option('--json')
740
783
  .action(async (id, opts) => {
741
784
  const { runDbGet } = await import('./commands/products-db.js');
742
785
  await runDbGet(id, { json: !!opts.json });
743
786
  });
744
787
  productsDbCmd
745
- .command('status <id> <status>')
746
- .description('Atualiza status (requested|provisioning|active|degraded|failed|archived)')
788
+ .command('status [id] [status]')
789
+ .description('Atualizar status de um banco de produto')
747
790
  .option('--reason <text>')
748
791
  .option('--json')
749
792
  .action(async (id, status, opts) => {
@@ -751,24 +794,24 @@ productsDbCmd
751
794
  await runDbStatus(id, status, { reason: opts.reason, json: !!opts.json });
752
795
  });
753
796
  productsDbCmd
754
- .command('retry <id>')
755
- .description('Re-enfileira provisionamento (status failed/degraded → requested)')
797
+ .command('retry [id]')
798
+ .description('Reenfileirar provisionamento de banco')
756
799
  .option('--json')
757
800
  .action(async (id, opts) => {
758
801
  const { runDbRetry } = await import('./commands/products-db.js');
759
802
  await runDbRetry(id, { json: !!opts.json });
760
803
  });
761
804
  productsDbCmd
762
- .command('rotate <id>')
763
- .description('Rotaciona credenciais (admin; Phase A: intent + audit)')
805
+ .command('rotate [id]')
806
+ .description('Rotacionar credenciais do banco (admin)')
764
807
  .option('--json')
765
808
  .action(async (id, opts) => {
766
809
  const { runDbRotate } = await import('./commands/products-db.js');
767
810
  await runDbRotate(id, { json: !!opts.json });
768
811
  });
769
812
  productsDbCmd
770
- .command('delete <id>')
771
- .description('Arquiva o banco (soft-delete; admin)')
813
+ .command('delete [id]')
814
+ .description('Arquivar banco por soft-delete (admin)')
772
815
  .option('--json')
773
816
  .action(async (id, opts) => {
774
817
  const { runDbDelete } = await import('./commands/products-db.js');
@@ -777,7 +820,7 @@ productsDbCmd
777
820
  // ── neetru logs ───────────────────────────────────────────────────────
778
821
  program
779
822
  .command('logs')
780
- .description('Visualiza logs do workspace; suporta tail contínuo')
823
+ .description('Visualizar logs do workspace (suporta tail contínuo)')
781
824
  .option('--client-id <id>', 'oauthClientId do workspace')
782
825
  .option('-f, --follow', 'tail contínuo (poll a cada 5s)')
783
826
  .option('-n, --lines <count>', 'número de linhas a buscar', '50')
@@ -802,7 +845,7 @@ program
802
845
  // ── neetru validate ───────────────────────────────────────────────────
803
846
  program
804
847
  .command('validate')
805
- .description('Health check da config local + conexão com Core')
848
+ .description('Validar config local e conexão com o Core')
806
849
  .action(async () => {
807
850
  const { runValidate } = await import('./commands/validate.js');
808
851
  await runValidate();
@@ -810,7 +853,7 @@ program
810
853
  // ── neetru open ───────────────────────────────────────────────────────
811
854
  program
812
855
  .command('open [target]')
813
- .description('Abre uma página do painel Neetru no browser')
856
+ .description('Abrir página do painel Neetru no browser')
814
857
  .option('--client-id <id>', 'oauthClientId do workspace (anexa em targets workspace-scoped)')
815
858
  .action(async (target, opts) => {
816
859
  const { runOpen } = await import('./commands/open.js');
@@ -819,7 +862,7 @@ program
819
862
  // ── neetru publish ────────────────────────────────────────────────────
820
863
  program
821
864
  .command('publish')
822
- .description('Publica o produto no catálogo público da landing (public_products)')
865
+ .description('Publicar produto no catálogo público da landing')
823
866
  .option('--draft', 'salva como rascunho (published=false)')
824
867
  .option('--unpublish', 'remove o produto da landing (mantém o doc)')
825
868
  .option('--slug <slug>', 'override do slug do neetru.config.json')
@@ -850,7 +893,7 @@ program
850
893
  // ── neetru add ────────────────────────────────────────────────────────
851
894
  program
852
895
  .command('add <feature>')
853
- .description('v1.3 copia template (auth | billing | usage | users | support) pra src/lib/neetru/')
896
+ .description('Adicionar template de feature (auth/billing/usage/...)')
854
897
  .option('--force', 'sobrescrever arquivos existentes')
855
898
  .action(async (feature, opts) => {
856
899
  const { runAdd } = await import('./commands/add.js');
@@ -859,10 +902,10 @@ program
859
902
  // ── neetru mocks ──────────────────────────────────────────────────────
860
903
  const mocksCmd = program
861
904
  .command('mocks')
862
- .description('v1.3 gerenciar fixtures dev (NEETRU_ENV=dev)');
905
+ .description('Gerenciar fixtures de dev (NEETRU_ENV=dev)');
863
906
  mocksCmd
864
907
  .command('reset')
865
- .description('Reseta .neetru/dev-fixtures.json para {}')
908
+ .description('Resetar fixtures de dev para vazio')
866
909
  .action(async () => {
867
910
  const { runMocksReset } = await import('./commands/mocks.js');
868
911
  await runMocksReset();
@@ -870,10 +913,10 @@ mocksCmd
870
913
  // ── neetru env ────────────────────────────────────────────────────────
871
914
  const envCmd = program
872
915
  .command('env')
873
- .description('v1.3 — gerenciar configuração NEETRU_ENV no .env.local');
916
+ .description('Gerenciar NEETRU_ENV no .env.local');
874
917
  envCmd
875
918
  .command('switch <target>')
876
- .description('Alterna NEETRU_ENV: dev | workspace | production')
919
+ .description('Alternar NEETRU_ENV (dev/workspace/production)')
877
920
  .action(async (target) => {
878
921
  const { runEnvSwitch } = await import('./commands/env.js');
879
922
  await runEnvSwitch({ target });
@@ -881,10 +924,10 @@ envCmd
881
924
  // ── neetru db ─────────────────────────────────────────────────────────
882
925
  const dbCmd = program
883
926
  .command('db')
884
- .description('v1.4 gerência de schema/migrations/seed do produto');
927
+ .description('Gerenciar schema, migrations e seed do produto');
885
928
  dbCmd
886
929
  .command('init')
887
- .description('Cria manifest stub a partir de neetru.config.json')
930
+ .description('Criar manifest de schema a partir do config')
888
931
  .option('--out <path>', 'caminho do manifest (default db/schema.manifest.json)')
889
932
  .option('--force', 'sobrescreve se já existir')
890
933
  .action(async (opts) => {
@@ -893,7 +936,7 @@ dbCmd
893
936
  });
894
937
  dbCmd
895
938
  .command('migrate <toVersion>')
896
- .description('Aplica migration via Core (chama runMigrations Sprint 8)')
939
+ .description('Aplicar migration de schema via Core')
897
940
  .option('--from <fromVersion>', 'versão atual (default: schemaVersion do config)')
898
941
  .action(async (toVersion, opts) => {
899
942
  const { runDbMigrate } = await import('./commands/db.js');
@@ -901,7 +944,7 @@ dbCmd
901
944
  });
902
945
  dbCmd
903
946
  .command('seed')
904
- .description('Executa db/seed.ts no projeto (NEETRU_ENV=dev)')
947
+ .description('Executar script de seed do produto')
905
948
  .option('--script <path>', 'caminho custom do script de seed')
906
949
  .action(async (opts) => {
907
950
  const { runDbSeed } = await import('./commands/db.js');
@@ -910,10 +953,10 @@ dbCmd
910
953
  // ── neetru fn ─────────────────────────────────────────────────────────
911
954
  const fnCmd = program
912
955
  .command('fn')
913
- .description('v1.4 gestão de Functions/APIs do produto');
956
+ .description('Gerenciar Functions e APIs do produto');
914
957
  fnCmd
915
958
  .command('deploy')
916
- .description('Registra nova versão da API no catálogo neetru-apis (Sprint 7 stub)')
959
+ .description('Registrar nova versão da API no catálogo')
917
960
  .option('--version <v>', 'versão da API (default: apiVersion do config ou v1)')
918
961
  .option('--channel <channel>', 'stable | beta | alpha', 'stable')
919
962
  .option('--spec <path>', 'caminho de OpenAPI/JSON schema')
@@ -924,7 +967,7 @@ fnCmd
924
967
  // ── neetru promote ────────────────────────────────────────────────────
925
968
  program
926
969
  .command('promote')
927
- .description('v1.4 — solicita promotion entre ambientes (staff-gated). dev→workspace→beta→prod')
970
+ .description('Solicitar promotion entre ambientes (staff-gated)')
928
971
  .requiredOption('--from <env>', 'dev | workspace | beta | prod')
929
972
  .requiredOption('--to <env>', 'dev | workspace | beta | prod')
930
973
  .option('--product <slug>', 'override do slug do neetru.config.json')
@@ -945,7 +988,7 @@ program
945
988
  // ── neetru doctor ─────────────────────────────────────────────────────
946
989
  program
947
990
  .command('doctor')
948
- .description('v2.0 diagnóstico do CLI: token, core, schema, NEETRU_ENV, version')
991
+ .description('Diagnosticar saúde do CLI (token, core, schema, env)')
949
992
  .option('--json', 'saída em JSON (machine-readable)')
950
993
  .action(async (opts) => {
951
994
  const { runDoctor } = await import('./commands/doctor.js');
@@ -954,7 +997,7 @@ program
954
997
  // ── neetru upgrade ────────────────────────────────────────────────────
955
998
  program
956
999
  .command('upgrade')
957
- .description('v2.0 verifica latest no npm e exibe instrução de upgrade')
1000
+ .description('Verificar versão mais recente do CLI no npm')
958
1001
  .option('--json', 'saída em JSON')
959
1002
  .action(async (opts) => {
960
1003
  const { runUpgrade } = await import('./commands/upgrade.js');
@@ -963,7 +1006,7 @@ program
963
1006
  // ── neetru autocomplete ───────────────────────────────────────────────
964
1007
  program
965
1008
  .command('autocomplete <shell>')
966
- .description('v2.0 — gera script de shell completion (bash | zsh | pwsh)')
1009
+ .description('Gerar script de shell completion (bash/zsh/pwsh)')
967
1010
  .action(async (shell) => {
968
1011
  const { runAutocomplete } = await import('./commands/autocomplete.js');
969
1012
  await runAutocomplete(shell);
@@ -971,10 +1014,10 @@ program
971
1014
  // ── neetru agent release ──────────────────────────────────────────────
972
1015
  const agentCmd = program
973
1016
  .command('agent')
974
- .description('Operações sobre o binário do Neetru Agent (Linux daemon)');
1017
+ .description('Gerenciar binário do Neetru Agent (Linux daemon)');
975
1018
  agentCmd
976
1019
  .command('release')
977
- .description('Registra nova release do agente em agent_releases (Firestore)')
1020
+ .description('Registrar nova release do agente em agent_releases')
978
1021
  .requiredOption('--version <semver>', 'versão (ex: 1.2.0 ou 1.2.0-beta.1)')
979
1022
  .option('--channel <channel>', 'stable | beta | canary (default: beta)', 'beta')
980
1023
  .option('--changelog <text|@file>', 'changelog markdown inline ou "@path" pra ler de arquivo')
@@ -996,7 +1039,7 @@ agentCmd
996
1039
  });
997
1040
  agentCmd
998
1041
  .command('yank <version>')
999
- .description('Soft-revoke de uma release do agente (destrutivo top-tier confirmação + step-up MFA)')
1042
+ .description('Revogar release do agente (destrutivo — exige MFA)')
1000
1043
  .requiredOption('--reason <text>', 'motivo do yank (mínimo 5 caracteres)')
1001
1044
  .option('--yes', 'pula a confirmação interativa (modo script)')
1002
1045
  .option('--force', 'alias de --yes')
@@ -1016,10 +1059,10 @@ agentCmd
1016
1059
  });
1017
1060
  const agentCanaryCmd = agentCmd
1018
1061
  .command('canary')
1019
- .description('Controla o canary rollout de releases do agente');
1062
+ .description('Controlar canary rollout de releases do agente');
1020
1063
  agentCanaryCmd
1021
1064
  .command('start <version>')
1022
- .description('Inicia o canary rollout de uma release (phase1 = 5%)')
1065
+ .description('Iniciar canary rollout de uma release (phase1 5%)')
1023
1066
  .option('--json', 'saída em JSON')
1024
1067
  .action(async (version, opts) => {
1025
1068
  const { runAgentCanaryStart } = await import('./commands/agent-write.js');
@@ -1027,7 +1070,7 @@ agentCanaryCmd
1027
1070
  });
1028
1071
  agentCanaryCmd
1029
1072
  .command('rollback <version>')
1030
- .description('Rollback do canary de uma release (destrutivo top-tier confirmação + step-up MFA)')
1073
+ .description('Reverter canary de uma release (destrutivo — exige MFA)')
1031
1074
  .requiredOption('--reason <text>', 'motivo do rollback (mínimo 5 caracteres)')
1032
1075
  .option('--yes', 'pula a confirmação interativa (modo script)')
1033
1076
  .option('--force', 'alias de --yes')
@@ -1048,13 +1091,13 @@ agentCanaryCmd
1048
1091
  // ── neetru support ───────────────────────────────────────────────────
1049
1092
  const supportCmd = program
1050
1093
  .command('support')
1051
- .description('Support tickets inbox staff via CLI (F5 §4.2.6)');
1094
+ .description('Gerenciar suporte ao cliente via CLI');
1052
1095
  const supportTicketsCmd = supportCmd
1053
1096
  .command('tickets')
1054
- .description('Operações sobre support_tickets');
1097
+ .description('Operar tickets de suporte');
1055
1098
  supportTicketsCmd
1056
1099
  .command('list')
1057
- .description('Lista tickets com filtros')
1100
+ .description('Listar tickets de suporte')
1058
1101
  .option('--status <s>', 'open | in_progress | resolved | closed')
1059
1102
  .option('--severity <s>', 'sev1 | sev2 | sev3 | sev4')
1060
1103
  .option('--product <id>', 'filtra por productId')
@@ -1076,7 +1119,7 @@ supportTicketsCmd
1076
1119
  });
1077
1120
  supportTicketsCmd
1078
1121
  .command('describe <id>')
1079
- .description('Detalha um ticket + thread de mensagens')
1122
+ .description('Mostrar ticket com thread de mensagens')
1080
1123
  .option('--json', 'saída em JSON')
1081
1124
  .action(async (id, opts) => {
1082
1125
  const { runSupportTicketsDescribe } = await import('./commands/support.js');
@@ -1084,7 +1127,7 @@ supportTicketsCmd
1084
1127
  });
1085
1128
  supportTicketsCmd
1086
1129
  .command('reply <id>')
1087
- .description('Anexa mensagem staff ao ticket (transiciona open → in_progress se aplicável)')
1130
+ .description('Responder ticket com mensagem staff')
1088
1131
  .requiredOption('--message <text>', 'corpo da mensagem')
1089
1132
  .option('--json', 'saída em JSON')
1090
1133
  .action(async (id, opts) => {
@@ -1093,7 +1136,7 @@ supportTicketsCmd
1093
1136
  });
1094
1137
  supportTicketsCmd
1095
1138
  .command('assign <id>')
1096
- .description('Atribui ticket a um staff (uid)')
1139
+ .description('Atribuir ticket a um staff')
1097
1140
  .requiredOption('--to <staffUid>', 'uid do staff destino')
1098
1141
  .option('--json', 'saída em JSON')
1099
1142
  .action(async (id, opts) => {
@@ -1102,7 +1145,7 @@ supportTicketsCmd
1102
1145
  });
1103
1146
  supportTicketsCmd
1104
1147
  .command('status <id>')
1105
- .description('Transiciona status do ticket (FSM)')
1148
+ .description('Transicionar status do ticket')
1106
1149
  .requiredOption('--to <status>', 'open | in_progress | resolved | closed')
1107
1150
  .option('--json', 'saída em JSON')
1108
1151
  .action(async (id, opts) => {
@@ -1110,23 +1153,27 @@ supportTicketsCmd
1110
1153
  await runSupportTicketsStatus(id, { to: opts.to, json: !!opts.json });
1111
1154
  });
1112
1155
  // ── neetru dns ───────────────────────────────────────────────────────
1113
- const dnsCmd = program.command('dns').description('Cloud DNS — managed zones');
1114
- dnsCmd
1156
+ const dnsCmd = program
1157
+ .command('dns')
1158
+ .description('Gerenciar Cloud DNS managed zones');
1159
+ const dnsZonesCmd = dnsCmd
1115
1160
  .command('zones')
1116
- .description('Operações sobre managed zones')
1161
+ .description('Operar managed zones do Cloud DNS');
1162
+ dnsZonesCmd
1117
1163
  .command('list')
1118
- .description('Lista managed zones do projeto')
1164
+ .description('Listar managed zones do projeto')
1119
1165
  .option('--json', 'saída em JSON')
1120
1166
  .action(async (opts) => {
1121
1167
  const { runDnsZonesList } = await import('./commands/infra-read.js');
1122
1168
  await runDnsZonesList({ json: !!opts.json });
1123
1169
  });
1124
1170
  // ── neetru hosting ───────────────────────────────────────────────────
1125
- program
1171
+ const hostingCmd = program
1126
1172
  .command('hosting')
1127
- .description('Customer domains hosting setup')
1173
+ .description('Gerenciar customer domains e hosting setup');
1174
+ hostingCmd
1128
1175
  .command('list')
1129
- .description('Lista customer domains com scope de tenant aplicado')
1176
+ .description('Listar customer domains com scope de tenant')
1130
1177
  .option('--json', 'saída em JSON')
1131
1178
  .action(async (opts) => {
1132
1179
  const { runHostingList } = await import('./commands/infra-read.js');
@@ -1135,9 +1182,9 @@ program
1135
1182
  // ── neetru builds ────────────────────────────────────────────────────
1136
1183
  program
1137
1184
  .command('builds')
1138
- .description('Cloud Build — builds live (status + duração)')
1185
+ .description('Consultar Cloud Build (status e duração)')
1139
1186
  .command('list')
1140
- .description('Lista Cloud Builds recentes (global + regional)')
1187
+ .description('Listar Cloud Builds recentes (global e regional)')
1141
1188
  .option('--json', 'saída em JSON')
1142
1189
  .action(async (opts) => {
1143
1190
  const { runBuildsList } = await import('./commands/infra-read.js');
@@ -1147,13 +1194,13 @@ program
1147
1194
  // Disaster Recovery — listar exports + restore assistido (admin + step-up MFA).
1148
1195
  const drCmd = program
1149
1196
  .command('dr')
1150
- .description('Disaster Recovery — exports + restore (admin only, RUNBOOK_DR_DRILL)');
1197
+ .description('Operar Disaster Recovery (admin only)');
1151
1198
  const drExportsCmd = drCmd
1152
1199
  .command('exports')
1153
- .description('Operações sobre exports de Firestore em gs://neetru-backups');
1200
+ .description('Operar exports de Firestore em gs://neetru-backups');
1154
1201
  drExportsCmd
1155
1202
  .command('list')
1156
- .description('Lista exports disponíveis (sort: mais recente primeiro)')
1203
+ .description('Listar exports de DR disponíveis')
1157
1204
  .option('--json', 'saída em JSON')
1158
1205
  .action(async (opts) => {
1159
1206
  const { runDrExportsList } = await import('./commands/dr.js');
@@ -1161,7 +1208,7 @@ drExportsCmd
1161
1208
  });
1162
1209
  drCmd
1163
1210
  .command('restore')
1164
- .description('Dispara restore Firestore (IRREVERSÍVEL no destino destrutivo top-tier)')
1211
+ .description('Restaurar Firestore de export (IRREVERSÍVEL — exige MFA)')
1165
1212
  .requiredOption('--gcs-path <path>', 'gs://neetru-backups/firestore-exports/<stamp>/')
1166
1213
  .requiredOption('--target-project <project>', 'projeto GCP de destino (deve ser STAGING)')
1167
1214
  .option('--yes', 'pula a confirmação interativa (modo script)')
@@ -1181,10 +1228,24 @@ drCmd
1181
1228
  json: !!opts.json,
1182
1229
  });
1183
1230
  });
1231
+ // ── neetru schema ─────────────────────────────────────────────────────
1232
+ // Inspecionar spec OpenAPI do Core — usado pela IA e devs pra entender endpoints.
1233
+ {
1234
+ const { registerSchemaCommand } = await import('./commands/schema.js');
1235
+ registerSchemaCommand(program);
1236
+ }
1184
1237
  // ── parse ─────────────────────────────────────────────────────────────
1185
- program.parse(process.argv);
1186
1238
  if (!process.argv.slice(2).length) {
1187
- log.banner();
1188
- program.outputHelp();
1239
+ if (process.stdin.isTTY && process.stdout.isTTY && process.env.CI !== 'true') {
1240
+ const { runTerminalUi } = await import('./commands/ui.js');
1241
+ await runTerminalUi();
1242
+ }
1243
+ else {
1244
+ log.banner();
1245
+ program.outputHelp();
1246
+ }
1247
+ }
1248
+ else {
1249
+ program.parse(process.argv);
1189
1250
  }
1190
1251
  //# sourceMappingURL=index.js.map