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