@neetru/cli 2.2.0 → 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/commands/ai.js +82 -10
- package/dist/commands/ai.js.map +1 -1
- package/dist/commands/auth.d.ts +19 -0
- package/dist/commands/auth.js +203 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/index.js +134 -105
- package/dist/index.js.map +1 -1
- package/dist/lib/ai/auth-discovery.d.ts +26 -0
- package/dist/lib/ai/auth-discovery.js +256 -0
- package/dist/lib/ai/auth-discovery.js.map +1 -0
- package/dist/lib/ai/orchestrator.d.ts +25 -0
- package/dist/lib/ai/orchestrator.js +167 -28
- package/dist/lib/ai/orchestrator.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,12 +5,12 @@ import { CLI_VERSION } from './version.js';
|
|
|
5
5
|
const program = new Command();
|
|
6
6
|
program
|
|
7
7
|
.name('neetru')
|
|
8
|
-
.description('Neetru Developer Kit
|
|
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
|
|
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');
|
|
@@ -20,7 +20,7 @@ program
|
|
|
20
20
|
// v2.1.1 — prompt interativo de caminho + merge mode + preserva arquivos
|
|
21
21
|
program
|
|
22
22
|
.command('init <name>')
|
|
23
|
-
.description('
|
|
23
|
+
.description('Inicializar scaffold de produto SaaS Neetru')
|
|
24
24
|
.option('--type <type>', 'nextjs | node-api', 'nextjs')
|
|
25
25
|
.option('--here', 'init no cwd atual (modo merge — preserva existentes)')
|
|
26
26
|
.option('--path <path>', 'custom path target')
|
|
@@ -41,7 +41,7 @@ program
|
|
|
41
41
|
// Cria produto + workspace + scaffold local + abre painel — single command.
|
|
42
42
|
program
|
|
43
43
|
.command('new <name>')
|
|
44
|
-
.description('
|
|
44
|
+
.description('Criar produto, workspace, scaffold e abrir painel')
|
|
45
45
|
.option('--product-slug <slug>', 'slug do produto (default: derivado de <name>)')
|
|
46
46
|
.option('--env <env>', 'dev (default) | staging | prod', 'dev')
|
|
47
47
|
.option('--tier <tier>', 'standard (default) | dev | enterprise', 'standard')
|
|
@@ -61,27 +61,56 @@ program
|
|
|
61
61
|
json: !!opts.json,
|
|
62
62
|
});
|
|
63
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
|
+
});
|
|
64
93
|
// ── neetru config ─────────────────────────────────────────────────────
|
|
65
94
|
const configCmd = program
|
|
66
95
|
.command('config')
|
|
67
|
-
.description('Gerenciar configurações do CLI
|
|
96
|
+
.description('Gerenciar configurações do CLI');
|
|
68
97
|
configCmd
|
|
69
98
|
.command('set <key> <value>')
|
|
70
|
-
.description('
|
|
99
|
+
.description('Definir valor de configuração')
|
|
71
100
|
.action(async (key, value) => {
|
|
72
101
|
const { configSet } = await import('./commands/config.js');
|
|
73
102
|
configSet(key, value);
|
|
74
103
|
});
|
|
75
104
|
configCmd
|
|
76
105
|
.command('get [key]')
|
|
77
|
-
.description('
|
|
106
|
+
.description('Ler configuração por chave (ou todas)')
|
|
78
107
|
.action(async (key) => {
|
|
79
108
|
const { configGet } = await import('./commands/config.js');
|
|
80
109
|
configGet(key);
|
|
81
110
|
});
|
|
82
111
|
configCmd
|
|
83
112
|
.command('path')
|
|
84
|
-
.description('
|
|
113
|
+
.description('Mostrar caminho do arquivo de configuração')
|
|
85
114
|
.action(async () => {
|
|
86
115
|
const { configPath } = await import('./commands/config.js');
|
|
87
116
|
configPath();
|
|
@@ -89,7 +118,7 @@ configCmd
|
|
|
89
118
|
// ── neetru login ──────────────────────────────────────────────────────
|
|
90
119
|
program
|
|
91
120
|
.command('login')
|
|
92
|
-
.description('
|
|
121
|
+
.description('Autenticar CLI via Device Code OAuth (RFC 8628)')
|
|
93
122
|
.option('--token <token>', 'token nrt_<keyId>_<secret> (modo CI/legado, pula browser)')
|
|
94
123
|
.option('--json', 'saída em JSON (machine-readable)')
|
|
95
124
|
.action(async (opts) => {
|
|
@@ -99,7 +128,7 @@ program
|
|
|
99
128
|
// ── neetru logout ─────────────────────────────────────────────────────
|
|
100
129
|
program
|
|
101
130
|
.command('logout')
|
|
102
|
-
.description('
|
|
131
|
+
.description('Remover credenciais locais do CLI')
|
|
103
132
|
.action(async () => {
|
|
104
133
|
const { runLogout } = await import('./commands/logout.js');
|
|
105
134
|
await runLogout();
|
|
@@ -107,7 +136,7 @@ program
|
|
|
107
136
|
// ── neetru whoami ─────────────────────────────────────────────────────
|
|
108
137
|
program
|
|
109
138
|
.command('whoami')
|
|
110
|
-
.description('
|
|
139
|
+
.description('Mostrar identidade da chave CLI corrente')
|
|
111
140
|
.option('--json', 'saída em JSON')
|
|
112
141
|
.action(async (opts) => {
|
|
113
142
|
const { runWhoami } = await import('./commands/whoami.js');
|
|
@@ -116,7 +145,7 @@ program
|
|
|
116
145
|
// ── neetru build ──────────────────────────────────────────────────────
|
|
117
146
|
program
|
|
118
147
|
.command('build')
|
|
119
|
-
.description('
|
|
148
|
+
.description('Construir tarball do produto pronto para deploy')
|
|
120
149
|
.option('--product <slug>', 'override do slug (default: lê neetru.config.json)')
|
|
121
150
|
.option('--stack <stack>', 'node | docker | php-apache | static (default: detectado)')
|
|
122
151
|
.option('--output <dir>', 'diretório de saída', '.neetru-build')
|
|
@@ -135,7 +164,7 @@ program
|
|
|
135
164
|
// ── neetru deploy ─────────────────────────────────────────────────────
|
|
136
165
|
program
|
|
137
166
|
.command('deploy')
|
|
138
|
-
.description('
|
|
167
|
+
.description('Deployar produto via pipeline do Neetru Core')
|
|
139
168
|
.option('--product <slug>', 'slug do produto')
|
|
140
169
|
.option('--version <version>', 'versão a deployar')
|
|
141
170
|
.option('--stack <stack>', 'node | docker | php-apache | static')
|
|
@@ -174,7 +203,7 @@ program
|
|
|
174
203
|
// delega ao status de workspace legado (backward-compat).
|
|
175
204
|
program
|
|
176
205
|
.command('status')
|
|
177
|
-
.description('
|
|
206
|
+
.description('Verificar saúde das superfícies públicas do Core')
|
|
178
207
|
.option('--client-id <id>', 'oauthClientId do workspace (status de workspace legado)')
|
|
179
208
|
.option('--json', 'saída em JSON')
|
|
180
209
|
.action(async (opts) => {
|
|
@@ -184,10 +213,10 @@ program
|
|
|
184
213
|
// ── neetru tenants ────────────────────────────────────────────────────
|
|
185
214
|
const tenantsCmd = program
|
|
186
215
|
.command('tenants')
|
|
187
|
-
.description('
|
|
216
|
+
.description('Gerenciar tenants (read-only)');
|
|
188
217
|
tenantsCmd
|
|
189
218
|
.command('list')
|
|
190
|
-
.description('
|
|
219
|
+
.description('Listar tenants')
|
|
191
220
|
.option('--status <status>', 'ativo | em provisionamento | suspenso | arquivado')
|
|
192
221
|
.option('--product <productId>', 'filtra por productId')
|
|
193
222
|
.option('--limit <n>', 'máximo de resultados (default 100, max 500)')
|
|
@@ -203,7 +232,7 @@ tenantsCmd
|
|
|
203
232
|
});
|
|
204
233
|
tenantsCmd
|
|
205
234
|
.command('get <id>')
|
|
206
|
-
.description('
|
|
235
|
+
.description('Mostrar detalhes de um tenant')
|
|
207
236
|
.option('--json', 'saída em JSON')
|
|
208
237
|
.action(async (id, opts) => {
|
|
209
238
|
const { runTenantsGet } = await import('./commands/tenants.js');
|
|
@@ -211,7 +240,7 @@ tenantsCmd
|
|
|
211
240
|
});
|
|
212
241
|
tenantsCmd
|
|
213
242
|
.command('create')
|
|
214
|
-
.description('
|
|
243
|
+
.description('Criar tenant (status inicial: em provisionamento)')
|
|
215
244
|
.requiredOption('--name <name>', 'nome do tenant')
|
|
216
245
|
.requiredOption('--slug <slug>', 'slug do tenant')
|
|
217
246
|
.requiredOption('--customer <customerId>', 'id do customer')
|
|
@@ -233,7 +262,7 @@ tenantsCmd
|
|
|
233
262
|
});
|
|
234
263
|
tenantsCmd
|
|
235
264
|
.command('update <id>')
|
|
236
|
-
.description('
|
|
265
|
+
.description('Atualizar dados de um tenant')
|
|
237
266
|
.requiredOption('--name <name>', 'nome do tenant')
|
|
238
267
|
.requiredOption('--slug <slug>', 'slug do tenant')
|
|
239
268
|
.requiredOption('--customer <customerId>', 'id do customer')
|
|
@@ -255,7 +284,7 @@ tenantsCmd
|
|
|
255
284
|
});
|
|
256
285
|
tenantsCmd
|
|
257
286
|
.command('suspend <id>')
|
|
258
|
-
.description('
|
|
287
|
+
.description('Suspender tenant (destrutivo — exige confirmação)')
|
|
259
288
|
.option('--yes', 'pula a confirmação interativa (modo script)')
|
|
260
289
|
.option('--force', 'alias de --yes')
|
|
261
290
|
.option('--json', 'saída em JSON')
|
|
@@ -265,7 +294,7 @@ tenantsCmd
|
|
|
265
294
|
});
|
|
266
295
|
tenantsCmd
|
|
267
296
|
.command('reactivate <id>')
|
|
268
|
-
.description('
|
|
297
|
+
.description('Reativar tenant suspenso')
|
|
269
298
|
.option('--json', 'saída em JSON')
|
|
270
299
|
.action(async (id, opts) => {
|
|
271
300
|
const { runTenantsReactivate } = await import('./commands/tenants.js');
|
|
@@ -274,10 +303,10 @@ tenantsCmd
|
|
|
274
303
|
// ── neetru audit ──────────────────────────────────────────────────────
|
|
275
304
|
const auditCmd = program
|
|
276
305
|
.command('audit')
|
|
277
|
-
.description('
|
|
306
|
+
.description('Consultar trilha de auditoria do Core (read-only)');
|
|
278
307
|
auditCmd
|
|
279
308
|
.command('tail')
|
|
280
|
-
.description('
|
|
309
|
+
.description('Listar últimos eventos de audit_logs')
|
|
281
310
|
.option('-n, --limit <n>', 'número de eventos (default 50, max 200)')
|
|
282
311
|
.option('--action <substring>', 'filtra por substring da ação (ex: billing, tenant.create)')
|
|
283
312
|
.option('--severity <level>', 'info | warning | critical')
|
|
@@ -296,10 +325,10 @@ auditCmd
|
|
|
296
325
|
// ── neetru billing ────────────────────────────────────────────────────
|
|
297
326
|
const billingCmd = program
|
|
298
327
|
.command('billing')
|
|
299
|
-
.description('
|
|
328
|
+
.description('Consultar billing e contabilidade (read-only)');
|
|
300
329
|
billingCmd
|
|
301
330
|
.command('summary')
|
|
302
|
-
.description('
|
|
331
|
+
.description('Mostrar sumário contábil do mês (MRR, invoices, subs)')
|
|
303
332
|
.option('--year <YYYY>', 'ano (default: corrente)')
|
|
304
333
|
.option('--month <1-12>', 'mês (default: corrente)')
|
|
305
334
|
.option('--json', 'saída em JSON')
|
|
@@ -310,10 +339,10 @@ billingCmd
|
|
|
310
339
|
// ── neetru servers ────────────────────────────────────────────────────
|
|
311
340
|
const serversCmd = program
|
|
312
341
|
.command('servers')
|
|
313
|
-
.description('
|
|
342
|
+
.description('Gerenciar servers e inventário de VMs');
|
|
314
343
|
serversCmd
|
|
315
344
|
.command('list')
|
|
316
|
-
.description('
|
|
345
|
+
.description('Listar servers')
|
|
317
346
|
.option('--status <status>', 'online (operacional + heartbeat fresco)')
|
|
318
347
|
.option('--provider <provider>', 'hetzner | digitalocean | aws | ...')
|
|
319
348
|
.option('--capacity', 'inclui colunas de RAM/CPU/disco')
|
|
@@ -329,7 +358,7 @@ serversCmd
|
|
|
329
358
|
});
|
|
330
359
|
serversCmd
|
|
331
360
|
.command('provision')
|
|
332
|
-
.description('
|
|
361
|
+
.description('Provisionar VM GCP e gerar registration token (admin)')
|
|
333
362
|
.requiredOption('--name <name>', 'nome do servidor')
|
|
334
363
|
.requiredOption('--zone <zone>', 'zona GCP (ex: us-central1-a)')
|
|
335
364
|
.requiredOption('--machine-type <type>', 'machine type GCP (ex: e2-small)')
|
|
@@ -349,7 +378,7 @@ serversCmd
|
|
|
349
378
|
});
|
|
350
379
|
serversCmd
|
|
351
380
|
.command('deactivate <serverId>')
|
|
352
|
-
.description('
|
|
381
|
+
.description('Desativar server (destrutivo top-tier — exige MFA)')
|
|
353
382
|
.option('--yes', 'pula a confirmação interativa (modo script)')
|
|
354
383
|
.option('--force', 'alias de --yes')
|
|
355
384
|
.option('--dry-run', 'valida e mostra o efeito sem aplicar')
|
|
@@ -367,7 +396,7 @@ serversCmd
|
|
|
367
396
|
});
|
|
368
397
|
serversCmd
|
|
369
398
|
.command('dispatch <serverId> <commandType>')
|
|
370
|
-
.description('
|
|
399
|
+
.description('Enfileirar comando para o agente Linux do server')
|
|
371
400
|
.option('--params <json>', 'objeto JSON de params do comando')
|
|
372
401
|
.option('--json', 'saída em JSON')
|
|
373
402
|
.action(async (id, commandType, opts) => {
|
|
@@ -377,10 +406,10 @@ serversCmd
|
|
|
377
406
|
// ── neetru workspaces ─────────────────────────────────────────────────
|
|
378
407
|
const workspacesCmd = program
|
|
379
408
|
.command('workspaces')
|
|
380
|
-
.description('
|
|
409
|
+
.description('Gerenciar workspaces compartilhados');
|
|
381
410
|
workspacesCmd
|
|
382
411
|
.command('create')
|
|
383
|
-
.description('
|
|
412
|
+
.description('Criar workspace (retorna OAuth secret one-time)')
|
|
384
413
|
.requiredOption('--product <productId>', 'id do produto')
|
|
385
414
|
.requiredOption('--customer <customerId>', 'id do customer')
|
|
386
415
|
.requiredOption('--env <env>', 'dev | staging | prod')
|
|
@@ -400,7 +429,7 @@ workspacesCmd
|
|
|
400
429
|
});
|
|
401
430
|
workspacesCmd
|
|
402
431
|
.command('advance <workspaceId>')
|
|
403
|
-
.description('
|
|
432
|
+
.description('Promover versão de bundle para running no workspace')
|
|
404
433
|
.requiredOption('--product <slug>', 'productSlug do bundle')
|
|
405
434
|
.requiredOption('--version <version>', 'versão do bundle a ativar')
|
|
406
435
|
.option('--json', 'saída em JSON')
|
|
@@ -414,7 +443,7 @@ workspacesCmd
|
|
|
414
443
|
});
|
|
415
444
|
workspacesCmd
|
|
416
445
|
.command('list')
|
|
417
|
-
.description('
|
|
446
|
+
.description('Listar workspaces')
|
|
418
447
|
.option('--product <productId>', 'filtra por productId')
|
|
419
448
|
.option('--env <env>', 'dev | staging | prod')
|
|
420
449
|
.option('--status <status>', 'active | paused | provisioning | …')
|
|
@@ -430,7 +459,7 @@ workspacesCmd
|
|
|
430
459
|
});
|
|
431
460
|
workspacesCmd
|
|
432
461
|
.command('get <workspaceId>')
|
|
433
|
-
.description('
|
|
462
|
+
.description('Mostrar detalhes de um workspace')
|
|
434
463
|
.option('--json', 'saída em JSON')
|
|
435
464
|
.action(async (id, opts) => {
|
|
436
465
|
const { runWorkspacesGet } = await import('./commands/workspaces.js');
|
|
@@ -438,7 +467,7 @@ workspacesCmd
|
|
|
438
467
|
});
|
|
439
468
|
workspacesCmd
|
|
440
469
|
.command('open <workspaceId>')
|
|
441
|
-
.description('
|
|
470
|
+
.description('Abrir painel do workspace no browser')
|
|
442
471
|
.action(async (id) => {
|
|
443
472
|
const { runWorkspacesOpen } = await import('./commands/workspaces.js');
|
|
444
473
|
await runWorkspacesOpen(id);
|
|
@@ -446,10 +475,10 @@ workspacesCmd
|
|
|
446
475
|
// ── neetru deployments ────────────────────────────────────────────────
|
|
447
476
|
const deploymentsCmd = program
|
|
448
477
|
.command('deployments')
|
|
449
|
-
.description('
|
|
478
|
+
.description('Gerenciar deployments do Core');
|
|
450
479
|
deploymentsCmd
|
|
451
480
|
.command('create')
|
|
452
|
-
.description('
|
|
481
|
+
.description('Criar deployment (dispara comando para o agente)')
|
|
453
482
|
.requiredOption('--product <productId>', 'id do produto')
|
|
454
483
|
.requiredOption('--tenant <tenantId>', 'id do tenant alvo')
|
|
455
484
|
.requiredOption('--version <version>', 'versão a deployar')
|
|
@@ -469,7 +498,7 @@ deploymentsCmd
|
|
|
469
498
|
});
|
|
470
499
|
deploymentsCmd
|
|
471
500
|
.command('rollback <deploymentId>')
|
|
472
|
-
.description('
|
|
501
|
+
.description('Reverter deployment (destrutivo top-tier — exige MFA)')
|
|
473
502
|
.option('--yes', 'pula a confirmação interativa (modo script)')
|
|
474
503
|
.option('--force', 'alias de --yes')
|
|
475
504
|
.option('--dry-run', 'valida e mostra o efeito sem aplicar')
|
|
@@ -488,10 +517,10 @@ deploymentsCmd
|
|
|
488
517
|
// ── neetru cloud-run ──────────────────────────────────────────────────
|
|
489
518
|
const cloudRunCmd = program
|
|
490
519
|
.command('cloud-run')
|
|
491
|
-
.description('
|
|
520
|
+
.description('Gerenciar serviços Cloud Run (admin)');
|
|
492
521
|
cloudRunCmd
|
|
493
522
|
.command('pause <service>')
|
|
494
|
-
.description('
|
|
523
|
+
.description('Pausar serviço Cloud Run (scale-to-zero)')
|
|
495
524
|
.option('--json', 'saída em JSON')
|
|
496
525
|
.action(async (service, opts) => {
|
|
497
526
|
const { runCloudRunPause } = await import('./commands/cloud-run.js');
|
|
@@ -499,7 +528,7 @@ cloudRunCmd
|
|
|
499
528
|
});
|
|
500
529
|
cloudRunCmd
|
|
501
530
|
.command('resume <service>')
|
|
502
|
-
.description('
|
|
531
|
+
.description('Retomar serviço Cloud Run pausado')
|
|
503
532
|
.option('--min-instances <n>', 'minInstanceCount')
|
|
504
533
|
.option('--max-instances <n>', 'maxInstanceCount')
|
|
505
534
|
.option('--json', 'saída em JSON')
|
|
@@ -513,7 +542,7 @@ cloudRunCmd
|
|
|
513
542
|
});
|
|
514
543
|
cloudRunCmd
|
|
515
544
|
.command('delete <service>')
|
|
516
|
-
.description('
|
|
545
|
+
.description('Remover serviço Cloud Run (IRREVERSÍVEL — exige MFA)')
|
|
517
546
|
.option('--yes', 'pula a confirmação interativa (modo script)')
|
|
518
547
|
.option('--force', 'alias de --yes')
|
|
519
548
|
.option('--dry-run', 'valida e mostra o efeito sem aplicar')
|
|
@@ -532,10 +561,10 @@ cloudRunCmd
|
|
|
532
561
|
// ── neetru api-catalog ────────────────────────────────────────────────
|
|
533
562
|
const apiCatalogCmd = program
|
|
534
563
|
.command('api-catalog')
|
|
535
|
-
.description('
|
|
564
|
+
.description('Gerenciar catálogo de APIs versionadas');
|
|
536
565
|
apiCatalogCmd
|
|
537
566
|
.command('create <slug>')
|
|
538
|
-
.description('
|
|
567
|
+
.description('Registrar nova API no catálogo')
|
|
539
568
|
.requiredOption('--name <name>', 'nome da API')
|
|
540
569
|
.requiredOption('--base-url <url>', 'base URL')
|
|
541
570
|
.requiredOption('--version <version>', 'versão')
|
|
@@ -565,7 +594,7 @@ apiCatalogCmd
|
|
|
565
594
|
});
|
|
566
595
|
apiCatalogCmd
|
|
567
596
|
.command('update <slug>')
|
|
568
|
-
.description('
|
|
597
|
+
.description('Atualizar entrada do catálogo (slug imutável)')
|
|
569
598
|
.requiredOption('--name <name>', 'nome da API')
|
|
570
599
|
.requiredOption('--base-url <url>', 'base URL')
|
|
571
600
|
.requiredOption('--version <version>', 'versão')
|
|
@@ -595,7 +624,7 @@ apiCatalogCmd
|
|
|
595
624
|
});
|
|
596
625
|
apiCatalogCmd
|
|
597
626
|
.command('archive <slug>')
|
|
598
|
-
.description('
|
|
627
|
+
.description('Arquivar API por soft-delete (--unarchive reverte)')
|
|
599
628
|
.option('--unarchive', 'reativa em vez de arquivar')
|
|
600
629
|
.option('--yes', 'pula a confirmação interativa (modo script)')
|
|
601
630
|
.option('--force', 'alias de --yes')
|
|
@@ -611,7 +640,7 @@ apiCatalogCmd
|
|
|
611
640
|
});
|
|
612
641
|
apiCatalogCmd
|
|
613
642
|
.command('delete <slug>')
|
|
614
|
-
.description('
|
|
643
|
+
.description('Remover API fisicamente (IRREVERSÍVEL — exige MFA)')
|
|
615
644
|
.option('--yes', 'pula a confirmação interativa (modo script)')
|
|
616
645
|
.option('--force', 'alias de --yes')
|
|
617
646
|
.option('--dry-run', 'valida e mostra o efeito sem aplicar')
|
|
@@ -630,10 +659,10 @@ apiCatalogCmd
|
|
|
630
659
|
// ── neetru products ───────────────────────────────────────────────────
|
|
631
660
|
const productsCmd = program
|
|
632
661
|
.command('products')
|
|
633
|
-
.description('
|
|
662
|
+
.description('Gerenciar registry de produtos SaaS internos');
|
|
634
663
|
productsCmd
|
|
635
664
|
.command('list')
|
|
636
|
-
.description('
|
|
665
|
+
.description('Listar produtos internos')
|
|
637
666
|
.option('--status <status>', 'ativo | beta | descontinuado')
|
|
638
667
|
.option('--limit <n>', 'máximo de resultados (default 100, max 500)')
|
|
639
668
|
.option('--json', 'saída em JSON')
|
|
@@ -643,7 +672,7 @@ productsCmd
|
|
|
643
672
|
});
|
|
644
673
|
productsCmd
|
|
645
674
|
.command('create')
|
|
646
|
-
.description('
|
|
675
|
+
.description('Criar produto SaaS interno (interativo por default)')
|
|
647
676
|
.option('--name <name>', 'nome do produto (interativo se ausente)')
|
|
648
677
|
.option('--slug <slug>', 'slug (auto-derivado de --name se ausente)')
|
|
649
678
|
.option('--description <text>', 'descrição (opcional)')
|
|
@@ -667,7 +696,7 @@ productsCmd
|
|
|
667
696
|
});
|
|
668
697
|
productsCmd
|
|
669
698
|
.command('publish <slug>')
|
|
670
|
-
.description('
|
|
699
|
+
.description('Publicar produto no catálogo público')
|
|
671
700
|
.option('--json', 'saída em JSON')
|
|
672
701
|
.action(async (slug, opts) => {
|
|
673
702
|
const { runProductsPublish } = await import('./commands/products.js');
|
|
@@ -675,7 +704,7 @@ productsCmd
|
|
|
675
704
|
});
|
|
676
705
|
productsCmd
|
|
677
706
|
.command('unpublish <slug>')
|
|
678
|
-
.description('
|
|
707
|
+
.description('Remover produto do catálogo público')
|
|
679
708
|
.option('--json', 'saída em JSON')
|
|
680
709
|
.action(async (slug, opts) => {
|
|
681
710
|
const { runProductsUnpublish } = await import('./commands/products.js');
|
|
@@ -684,10 +713,10 @@ productsCmd
|
|
|
684
713
|
// ── neetru products db (Phase A — per-product DB isolation) ────────────
|
|
685
714
|
const productsDbCmd = productsCmd
|
|
686
715
|
.command('db')
|
|
687
|
-
.description('
|
|
716
|
+
.description('Gerenciar bancos isolados por produto');
|
|
688
717
|
productsDbCmd
|
|
689
718
|
.command('list')
|
|
690
|
-
.description('
|
|
719
|
+
.description('Listar bancos de produtos')
|
|
691
720
|
.option('--product-id <id>')
|
|
692
721
|
.option('--engine <engine>')
|
|
693
722
|
.option('--status <status>')
|
|
@@ -703,7 +732,7 @@ productsDbCmd
|
|
|
703
732
|
});
|
|
704
733
|
productsDbCmd
|
|
705
734
|
.command('engines')
|
|
706
|
-
.description('
|
|
735
|
+
.description('Listar engines de banco suportados')
|
|
707
736
|
.option('--json')
|
|
708
737
|
.action(async (opts) => {
|
|
709
738
|
const { runDbEngines } = await import('./commands/products-db.js');
|
|
@@ -711,7 +740,7 @@ productsDbCmd
|
|
|
711
740
|
});
|
|
712
741
|
productsDbCmd
|
|
713
742
|
.command('create')
|
|
714
|
-
.description('
|
|
743
|
+
.description('Criar banco de produto (Phase A: registra + audit)')
|
|
715
744
|
.requiredOption('--product-id <id>')
|
|
716
745
|
.requiredOption('--label <label>')
|
|
717
746
|
.requiredOption('--engine <engine>', 'firestore-instance|cloud-sql-postgres|cloud-sql-mysql|vm-postgres-single|vm-postgres-cluster|vm-mysql-single|vm-mysql-cluster')
|
|
@@ -735,7 +764,7 @@ productsDbCmd
|
|
|
735
764
|
});
|
|
736
765
|
productsDbCmd
|
|
737
766
|
.command('get <id>')
|
|
738
|
-
.description('
|
|
767
|
+
.description('Mostrar detalhes de um banco')
|
|
739
768
|
.option('--json')
|
|
740
769
|
.action(async (id, opts) => {
|
|
741
770
|
const { runDbGet } = await import('./commands/products-db.js');
|
|
@@ -743,7 +772,7 @@ productsDbCmd
|
|
|
743
772
|
});
|
|
744
773
|
productsDbCmd
|
|
745
774
|
.command('status <id> <status>')
|
|
746
|
-
.description('
|
|
775
|
+
.description('Atualizar status de um banco de produto')
|
|
747
776
|
.option('--reason <text>')
|
|
748
777
|
.option('--json')
|
|
749
778
|
.action(async (id, status, opts) => {
|
|
@@ -752,7 +781,7 @@ productsDbCmd
|
|
|
752
781
|
});
|
|
753
782
|
productsDbCmd
|
|
754
783
|
.command('retry <id>')
|
|
755
|
-
.description('
|
|
784
|
+
.description('Reenfileirar provisionamento de banco')
|
|
756
785
|
.option('--json')
|
|
757
786
|
.action(async (id, opts) => {
|
|
758
787
|
const { runDbRetry } = await import('./commands/products-db.js');
|
|
@@ -760,7 +789,7 @@ productsDbCmd
|
|
|
760
789
|
});
|
|
761
790
|
productsDbCmd
|
|
762
791
|
.command('rotate <id>')
|
|
763
|
-
.description('
|
|
792
|
+
.description('Rotacionar credenciais do banco (admin)')
|
|
764
793
|
.option('--json')
|
|
765
794
|
.action(async (id, opts) => {
|
|
766
795
|
const { runDbRotate } = await import('./commands/products-db.js');
|
|
@@ -768,7 +797,7 @@ productsDbCmd
|
|
|
768
797
|
});
|
|
769
798
|
productsDbCmd
|
|
770
799
|
.command('delete <id>')
|
|
771
|
-
.description('
|
|
800
|
+
.description('Arquivar banco por soft-delete (admin)')
|
|
772
801
|
.option('--json')
|
|
773
802
|
.action(async (id, opts) => {
|
|
774
803
|
const { runDbDelete } = await import('./commands/products-db.js');
|
|
@@ -777,7 +806,7 @@ productsDbCmd
|
|
|
777
806
|
// ── neetru logs ───────────────────────────────────────────────────────
|
|
778
807
|
program
|
|
779
808
|
.command('logs')
|
|
780
|
-
.description('
|
|
809
|
+
.description('Visualizar logs do workspace (suporta tail contínuo)')
|
|
781
810
|
.option('--client-id <id>', 'oauthClientId do workspace')
|
|
782
811
|
.option('-f, --follow', 'tail contínuo (poll a cada 5s)')
|
|
783
812
|
.option('-n, --lines <count>', 'número de linhas a buscar', '50')
|
|
@@ -802,7 +831,7 @@ program
|
|
|
802
831
|
// ── neetru validate ───────────────────────────────────────────────────
|
|
803
832
|
program
|
|
804
833
|
.command('validate')
|
|
805
|
-
.description('
|
|
834
|
+
.description('Validar config local e conexão com o Core')
|
|
806
835
|
.action(async () => {
|
|
807
836
|
const { runValidate } = await import('./commands/validate.js');
|
|
808
837
|
await runValidate();
|
|
@@ -810,7 +839,7 @@ program
|
|
|
810
839
|
// ── neetru open ───────────────────────────────────────────────────────
|
|
811
840
|
program
|
|
812
841
|
.command('open [target]')
|
|
813
|
-
.description('
|
|
842
|
+
.description('Abrir página do painel Neetru no browser')
|
|
814
843
|
.option('--client-id <id>', 'oauthClientId do workspace (anexa em targets workspace-scoped)')
|
|
815
844
|
.action(async (target, opts) => {
|
|
816
845
|
const { runOpen } = await import('./commands/open.js');
|
|
@@ -819,7 +848,7 @@ program
|
|
|
819
848
|
// ── neetru publish ────────────────────────────────────────────────────
|
|
820
849
|
program
|
|
821
850
|
.command('publish')
|
|
822
|
-
.description('
|
|
851
|
+
.description('Publicar produto no catálogo público da landing')
|
|
823
852
|
.option('--draft', 'salva como rascunho (published=false)')
|
|
824
853
|
.option('--unpublish', 'remove o produto da landing (mantém o doc)')
|
|
825
854
|
.option('--slug <slug>', 'override do slug do neetru.config.json')
|
|
@@ -850,7 +879,7 @@ program
|
|
|
850
879
|
// ── neetru add ────────────────────────────────────────────────────────
|
|
851
880
|
program
|
|
852
881
|
.command('add <feature>')
|
|
853
|
-
.description('
|
|
882
|
+
.description('Adicionar template de feature (auth/billing/usage/...)')
|
|
854
883
|
.option('--force', 'sobrescrever arquivos existentes')
|
|
855
884
|
.action(async (feature, opts) => {
|
|
856
885
|
const { runAdd } = await import('./commands/add.js');
|
|
@@ -859,10 +888,10 @@ program
|
|
|
859
888
|
// ── neetru mocks ──────────────────────────────────────────────────────
|
|
860
889
|
const mocksCmd = program
|
|
861
890
|
.command('mocks')
|
|
862
|
-
.description('
|
|
891
|
+
.description('Gerenciar fixtures de dev (NEETRU_ENV=dev)');
|
|
863
892
|
mocksCmd
|
|
864
893
|
.command('reset')
|
|
865
|
-
.description('
|
|
894
|
+
.description('Resetar fixtures de dev para vazio')
|
|
866
895
|
.action(async () => {
|
|
867
896
|
const { runMocksReset } = await import('./commands/mocks.js');
|
|
868
897
|
await runMocksReset();
|
|
@@ -870,10 +899,10 @@ mocksCmd
|
|
|
870
899
|
// ── neetru env ────────────────────────────────────────────────────────
|
|
871
900
|
const envCmd = program
|
|
872
901
|
.command('env')
|
|
873
|
-
.description('
|
|
902
|
+
.description('Gerenciar NEETRU_ENV no .env.local');
|
|
874
903
|
envCmd
|
|
875
904
|
.command('switch <target>')
|
|
876
|
-
.description('
|
|
905
|
+
.description('Alternar NEETRU_ENV (dev/workspace/production)')
|
|
877
906
|
.action(async (target) => {
|
|
878
907
|
const { runEnvSwitch } = await import('./commands/env.js');
|
|
879
908
|
await runEnvSwitch({ target });
|
|
@@ -881,10 +910,10 @@ envCmd
|
|
|
881
910
|
// ── neetru db ─────────────────────────────────────────────────────────
|
|
882
911
|
const dbCmd = program
|
|
883
912
|
.command('db')
|
|
884
|
-
.description('
|
|
913
|
+
.description('Gerenciar schema, migrations e seed do produto');
|
|
885
914
|
dbCmd
|
|
886
915
|
.command('init')
|
|
887
|
-
.description('
|
|
916
|
+
.description('Criar manifest de schema a partir do config')
|
|
888
917
|
.option('--out <path>', 'caminho do manifest (default db/schema.manifest.json)')
|
|
889
918
|
.option('--force', 'sobrescreve se já existir')
|
|
890
919
|
.action(async (opts) => {
|
|
@@ -893,7 +922,7 @@ dbCmd
|
|
|
893
922
|
});
|
|
894
923
|
dbCmd
|
|
895
924
|
.command('migrate <toVersion>')
|
|
896
|
-
.description('
|
|
925
|
+
.description('Aplicar migration de schema via Core')
|
|
897
926
|
.option('--from <fromVersion>', 'versão atual (default: schemaVersion do config)')
|
|
898
927
|
.action(async (toVersion, opts) => {
|
|
899
928
|
const { runDbMigrate } = await import('./commands/db.js');
|
|
@@ -901,7 +930,7 @@ dbCmd
|
|
|
901
930
|
});
|
|
902
931
|
dbCmd
|
|
903
932
|
.command('seed')
|
|
904
|
-
.description('
|
|
933
|
+
.description('Executar script de seed do produto')
|
|
905
934
|
.option('--script <path>', 'caminho custom do script de seed')
|
|
906
935
|
.action(async (opts) => {
|
|
907
936
|
const { runDbSeed } = await import('./commands/db.js');
|
|
@@ -910,10 +939,10 @@ dbCmd
|
|
|
910
939
|
// ── neetru fn ─────────────────────────────────────────────────────────
|
|
911
940
|
const fnCmd = program
|
|
912
941
|
.command('fn')
|
|
913
|
-
.description('
|
|
942
|
+
.description('Gerenciar Functions e APIs do produto');
|
|
914
943
|
fnCmd
|
|
915
944
|
.command('deploy')
|
|
916
|
-
.description('
|
|
945
|
+
.description('Registrar nova versão da API no catálogo')
|
|
917
946
|
.option('--version <v>', 'versão da API (default: apiVersion do config ou v1)')
|
|
918
947
|
.option('--channel <channel>', 'stable | beta | alpha', 'stable')
|
|
919
948
|
.option('--spec <path>', 'caminho de OpenAPI/JSON schema')
|
|
@@ -924,7 +953,7 @@ fnCmd
|
|
|
924
953
|
// ── neetru promote ────────────────────────────────────────────────────
|
|
925
954
|
program
|
|
926
955
|
.command('promote')
|
|
927
|
-
.description('
|
|
956
|
+
.description('Solicitar promotion entre ambientes (staff-gated)')
|
|
928
957
|
.requiredOption('--from <env>', 'dev | workspace | beta | prod')
|
|
929
958
|
.requiredOption('--to <env>', 'dev | workspace | beta | prod')
|
|
930
959
|
.option('--product <slug>', 'override do slug do neetru.config.json')
|
|
@@ -945,7 +974,7 @@ program
|
|
|
945
974
|
// ── neetru doctor ─────────────────────────────────────────────────────
|
|
946
975
|
program
|
|
947
976
|
.command('doctor')
|
|
948
|
-
.description('
|
|
977
|
+
.description('Diagnosticar saúde do CLI (token, core, schema, env)')
|
|
949
978
|
.option('--json', 'saída em JSON (machine-readable)')
|
|
950
979
|
.action(async (opts) => {
|
|
951
980
|
const { runDoctor } = await import('./commands/doctor.js');
|
|
@@ -954,7 +983,7 @@ program
|
|
|
954
983
|
// ── neetru upgrade ────────────────────────────────────────────────────
|
|
955
984
|
program
|
|
956
985
|
.command('upgrade')
|
|
957
|
-
.description('
|
|
986
|
+
.description('Verificar versão mais recente do CLI no npm')
|
|
958
987
|
.option('--json', 'saída em JSON')
|
|
959
988
|
.action(async (opts) => {
|
|
960
989
|
const { runUpgrade } = await import('./commands/upgrade.js');
|
|
@@ -963,7 +992,7 @@ program
|
|
|
963
992
|
// ── neetru autocomplete ───────────────────────────────────────────────
|
|
964
993
|
program
|
|
965
994
|
.command('autocomplete <shell>')
|
|
966
|
-
.description('
|
|
995
|
+
.description('Gerar script de shell completion (bash/zsh/pwsh)')
|
|
967
996
|
.action(async (shell) => {
|
|
968
997
|
const { runAutocomplete } = await import('./commands/autocomplete.js');
|
|
969
998
|
await runAutocomplete(shell);
|
|
@@ -971,10 +1000,10 @@ program
|
|
|
971
1000
|
// ── neetru agent release ──────────────────────────────────────────────
|
|
972
1001
|
const agentCmd = program
|
|
973
1002
|
.command('agent')
|
|
974
|
-
.description('
|
|
1003
|
+
.description('Gerenciar binário do Neetru Agent (Linux daemon)');
|
|
975
1004
|
agentCmd
|
|
976
1005
|
.command('release')
|
|
977
|
-
.description('
|
|
1006
|
+
.description('Registrar nova release do agente em agent_releases')
|
|
978
1007
|
.requiredOption('--version <semver>', 'versão (ex: 1.2.0 ou 1.2.0-beta.1)')
|
|
979
1008
|
.option('--channel <channel>', 'stable | beta | canary (default: beta)', 'beta')
|
|
980
1009
|
.option('--changelog <text|@file>', 'changelog markdown inline ou "@path" pra ler de arquivo')
|
|
@@ -996,7 +1025,7 @@ agentCmd
|
|
|
996
1025
|
});
|
|
997
1026
|
agentCmd
|
|
998
1027
|
.command('yank <version>')
|
|
999
|
-
.description('
|
|
1028
|
+
.description('Revogar release do agente (destrutivo — exige MFA)')
|
|
1000
1029
|
.requiredOption('--reason <text>', 'motivo do yank (mínimo 5 caracteres)')
|
|
1001
1030
|
.option('--yes', 'pula a confirmação interativa (modo script)')
|
|
1002
1031
|
.option('--force', 'alias de --yes')
|
|
@@ -1016,10 +1045,10 @@ agentCmd
|
|
|
1016
1045
|
});
|
|
1017
1046
|
const agentCanaryCmd = agentCmd
|
|
1018
1047
|
.command('canary')
|
|
1019
|
-
.description('
|
|
1048
|
+
.description('Controlar canary rollout de releases do agente');
|
|
1020
1049
|
agentCanaryCmd
|
|
1021
1050
|
.command('start <version>')
|
|
1022
|
-
.description('
|
|
1051
|
+
.description('Iniciar canary rollout de uma release (phase1 5%)')
|
|
1023
1052
|
.option('--json', 'saída em JSON')
|
|
1024
1053
|
.action(async (version, opts) => {
|
|
1025
1054
|
const { runAgentCanaryStart } = await import('./commands/agent-write.js');
|
|
@@ -1027,7 +1056,7 @@ agentCanaryCmd
|
|
|
1027
1056
|
});
|
|
1028
1057
|
agentCanaryCmd
|
|
1029
1058
|
.command('rollback <version>')
|
|
1030
|
-
.description('
|
|
1059
|
+
.description('Reverter canary de uma release (destrutivo — exige MFA)')
|
|
1031
1060
|
.requiredOption('--reason <text>', 'motivo do rollback (mínimo 5 caracteres)')
|
|
1032
1061
|
.option('--yes', 'pula a confirmação interativa (modo script)')
|
|
1033
1062
|
.option('--force', 'alias de --yes')
|
|
@@ -1048,13 +1077,13 @@ agentCanaryCmd
|
|
|
1048
1077
|
// ── neetru support ───────────────────────────────────────────────────
|
|
1049
1078
|
const supportCmd = program
|
|
1050
1079
|
.command('support')
|
|
1051
|
-
.description('
|
|
1080
|
+
.description('Gerenciar suporte ao cliente via CLI');
|
|
1052
1081
|
const supportTicketsCmd = supportCmd
|
|
1053
1082
|
.command('tickets')
|
|
1054
|
-
.description('
|
|
1083
|
+
.description('Operar tickets de suporte');
|
|
1055
1084
|
supportTicketsCmd
|
|
1056
1085
|
.command('list')
|
|
1057
|
-
.description('
|
|
1086
|
+
.description('Listar tickets de suporte')
|
|
1058
1087
|
.option('--status <s>', 'open | in_progress | resolved | closed')
|
|
1059
1088
|
.option('--severity <s>', 'sev1 | sev2 | sev3 | sev4')
|
|
1060
1089
|
.option('--product <id>', 'filtra por productId')
|
|
@@ -1076,7 +1105,7 @@ supportTicketsCmd
|
|
|
1076
1105
|
});
|
|
1077
1106
|
supportTicketsCmd
|
|
1078
1107
|
.command('describe <id>')
|
|
1079
|
-
.description('
|
|
1108
|
+
.description('Mostrar ticket com thread de mensagens')
|
|
1080
1109
|
.option('--json', 'saída em JSON')
|
|
1081
1110
|
.action(async (id, opts) => {
|
|
1082
1111
|
const { runSupportTicketsDescribe } = await import('./commands/support.js');
|
|
@@ -1084,7 +1113,7 @@ supportTicketsCmd
|
|
|
1084
1113
|
});
|
|
1085
1114
|
supportTicketsCmd
|
|
1086
1115
|
.command('reply <id>')
|
|
1087
|
-
.description('
|
|
1116
|
+
.description('Responder ticket com mensagem staff')
|
|
1088
1117
|
.requiredOption('--message <text>', 'corpo da mensagem')
|
|
1089
1118
|
.option('--json', 'saída em JSON')
|
|
1090
1119
|
.action(async (id, opts) => {
|
|
@@ -1093,7 +1122,7 @@ supportTicketsCmd
|
|
|
1093
1122
|
});
|
|
1094
1123
|
supportTicketsCmd
|
|
1095
1124
|
.command('assign <id>')
|
|
1096
|
-
.description('
|
|
1125
|
+
.description('Atribuir ticket a um staff')
|
|
1097
1126
|
.requiredOption('--to <staffUid>', 'uid do staff destino')
|
|
1098
1127
|
.option('--json', 'saída em JSON')
|
|
1099
1128
|
.action(async (id, opts) => {
|
|
@@ -1102,7 +1131,7 @@ supportTicketsCmd
|
|
|
1102
1131
|
});
|
|
1103
1132
|
supportTicketsCmd
|
|
1104
1133
|
.command('status <id>')
|
|
1105
|
-
.description('
|
|
1134
|
+
.description('Transicionar status do ticket')
|
|
1106
1135
|
.requiredOption('--to <status>', 'open | in_progress | resolved | closed')
|
|
1107
1136
|
.option('--json', 'saída em JSON')
|
|
1108
1137
|
.action(async (id, opts) => {
|
|
@@ -1110,12 +1139,12 @@ supportTicketsCmd
|
|
|
1110
1139
|
await runSupportTicketsStatus(id, { to: opts.to, json: !!opts.json });
|
|
1111
1140
|
});
|
|
1112
1141
|
// ── neetru dns ───────────────────────────────────────────────────────
|
|
1113
|
-
const dnsCmd = program.command('dns').description('Cloud DNS
|
|
1142
|
+
const dnsCmd = program.command('dns').description('Gerenciar Cloud DNS managed zones');
|
|
1114
1143
|
dnsCmd
|
|
1115
1144
|
.command('zones')
|
|
1116
|
-
.description('
|
|
1145
|
+
.description('Operar managed zones do Cloud DNS')
|
|
1117
1146
|
.command('list')
|
|
1118
|
-
.description('
|
|
1147
|
+
.description('Listar managed zones do projeto')
|
|
1119
1148
|
.option('--json', 'saída em JSON')
|
|
1120
1149
|
.action(async (opts) => {
|
|
1121
1150
|
const { runDnsZonesList } = await import('./commands/infra-read.js');
|
|
@@ -1124,9 +1153,9 @@ dnsCmd
|
|
|
1124
1153
|
// ── neetru hosting ───────────────────────────────────────────────────
|
|
1125
1154
|
program
|
|
1126
1155
|
.command('hosting')
|
|
1127
|
-
.description('
|
|
1156
|
+
.description('Gerenciar customer domains e hosting setup')
|
|
1128
1157
|
.command('list')
|
|
1129
|
-
.description('
|
|
1158
|
+
.description('Listar customer domains com scope de tenant')
|
|
1130
1159
|
.option('--json', 'saída em JSON')
|
|
1131
1160
|
.action(async (opts) => {
|
|
1132
1161
|
const { runHostingList } = await import('./commands/infra-read.js');
|
|
@@ -1135,9 +1164,9 @@ program
|
|
|
1135
1164
|
// ── neetru builds ────────────────────────────────────────────────────
|
|
1136
1165
|
program
|
|
1137
1166
|
.command('builds')
|
|
1138
|
-
.description('Cloud Build
|
|
1167
|
+
.description('Consultar Cloud Build (status e duração)')
|
|
1139
1168
|
.command('list')
|
|
1140
|
-
.description('
|
|
1169
|
+
.description('Listar Cloud Builds recentes (global e regional)')
|
|
1141
1170
|
.option('--json', 'saída em JSON')
|
|
1142
1171
|
.action(async (opts) => {
|
|
1143
1172
|
const { runBuildsList } = await import('./commands/infra-read.js');
|
|
@@ -1147,13 +1176,13 @@ program
|
|
|
1147
1176
|
// Disaster Recovery — listar exports + restore assistido (admin + step-up MFA).
|
|
1148
1177
|
const drCmd = program
|
|
1149
1178
|
.command('dr')
|
|
1150
|
-
.description('Disaster Recovery
|
|
1179
|
+
.description('Operar Disaster Recovery (admin only)');
|
|
1151
1180
|
const drExportsCmd = drCmd
|
|
1152
1181
|
.command('exports')
|
|
1153
|
-
.description('
|
|
1182
|
+
.description('Operar exports de Firestore em gs://neetru-backups');
|
|
1154
1183
|
drExportsCmd
|
|
1155
1184
|
.command('list')
|
|
1156
|
-
.description('
|
|
1185
|
+
.description('Listar exports de DR disponíveis')
|
|
1157
1186
|
.option('--json', 'saída em JSON')
|
|
1158
1187
|
.action(async (opts) => {
|
|
1159
1188
|
const { runDrExportsList } = await import('./commands/dr.js');
|
|
@@ -1161,7 +1190,7 @@ drExportsCmd
|
|
|
1161
1190
|
});
|
|
1162
1191
|
drCmd
|
|
1163
1192
|
.command('restore')
|
|
1164
|
-
.description('
|
|
1193
|
+
.description('Restaurar Firestore de export (IRREVERSÍVEL — exige MFA)')
|
|
1165
1194
|
.requiredOption('--gcs-path <path>', 'gs://neetru-backups/firestore-exports/<stamp>/')
|
|
1166
1195
|
.requiredOption('--target-project <project>', 'projeto GCP de destino (deve ser STAGING)')
|
|
1167
1196
|
.option('--yes', 'pula a confirmação interativa (modo script)')
|