@neetru/cli 2.7.5 → 2.9.1
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/CHANGELOG.md +316 -220
- package/README.md +137 -137
- package/dist/cli-kit/format.d.ts +49 -0
- package/dist/cli-kit/format.js +88 -0
- package/dist/cli-kit/format.js.map +1 -0
- package/dist/cli-kit/glyphs.d.ts +22 -0
- package/dist/cli-kit/glyphs.js +22 -0
- package/dist/cli-kit/glyphs.js.map +1 -0
- package/dist/cli-kit/index.d.ts +13 -0
- package/dist/cli-kit/index.js +12 -0
- package/dist/cli-kit/index.js.map +1 -0
- package/dist/cli-kit/palette.d.ts +10 -0
- package/dist/cli-kit/palette.js +36 -0
- package/dist/cli-kit/palette.js.map +1 -0
- package/dist/commands/ai.js +8 -8
- package/dist/commands/autocomplete.js +34 -34
- package/dist/commands/bug.d.ts +87 -0
- package/dist/commands/bug.js +419 -0
- package/dist/commands/bug.js.map +1 -0
- package/dist/commands/customers.d.ts +17 -0
- package/dist/commands/customers.js +160 -0
- package/dist/commands/customers.js.map +1 -0
- package/dist/commands/db.d.ts +91 -7
- package/dist/commands/db.js +898 -123
- package/dist/commands/db.js.map +1 -1
- package/dist/commands/deploy.d.ts +5 -0
- package/dist/commands/deploy.js +68 -0
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts +68 -0
- package/dist/commands/dev.js +345 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/docs.d.ts +4 -0
- package/dist/commands/docs.js +99 -7
- package/dist/commands/docs.js.map +1 -1
- package/dist/commands/doctor.js +4 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.js +121 -121
- package/dist/commands/marketplace.d.ts +36 -0
- package/dist/commands/marketplace.js +584 -0
- package/dist/commands/marketplace.js.map +1 -0
- package/dist/commands/new.d.ts +6 -0
- package/dist/commands/new.js +220 -40
- package/dist/commands/new.js.map +1 -1
- package/dist/commands/open.d.ts +8 -0
- package/dist/commands/open.js +61 -13
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/products-db.d.ts +1 -1
- package/dist/commands/products-db.js +17 -4
- package/dist/commands/products-db.js.map +1 -1
- package/dist/commands/products.d.ts +23 -0
- package/dist/commands/products.js +39 -1
- package/dist/commands/products.js.map +1 -1
- package/dist/commands/tenants.js +15 -0
- package/dist/commands/tenants.js.map +1 -1
- package/dist/commands/ui.d.ts +1 -1
- package/dist/commands/ui.js +172 -2
- package/dist/commands/ui.js.map +1 -1
- package/dist/commands/workspaces.d.ts +10 -1
- package/dist/commands/workspaces.js +136 -22
- package/dist/commands/workspaces.js.map +1 -1
- package/dist/index.js +532 -44
- package/dist/index.js.map +1 -1
- package/dist/lib/ai/context.js +90 -90
- package/dist/lib/config-schema.d.ts +8 -8
- package/dist/lib/db-local/db-json.d.ts +63 -0
- package/dist/lib/db-local/db-json.js +189 -0
- package/dist/lib/db-local/db-json.js.map +1 -0
- package/dist/lib/db-local/env.d.ts +26 -0
- package/dist/lib/db-local/env.js +64 -0
- package/dist/lib/db-local/env.js.map +1 -0
- package/dist/lib/db-local/fingerprint.d.ts +8 -0
- package/dist/lib/db-local/fingerprint.js +28 -0
- package/dist/lib/db-local/fingerprint.js.map +1 -0
- package/dist/lib/db-local/index.d.ts +15 -0
- package/dist/lib/db-local/index.js +14 -0
- package/dist/lib/db-local/index.js.map +1 -0
- package/dist/lib/db-pipeline/build-deps.d.ts +14 -0
- package/dist/lib/db-pipeline/build-deps.js +158 -0
- package/dist/lib/db-pipeline/build-deps.js.map +1 -0
- package/dist/lib/db-pipeline/errors.d.ts +29 -0
- package/dist/lib/db-pipeline/errors.js +29 -0
- package/dist/lib/db-pipeline/errors.js.map +1 -0
- package/dist/lib/db-pipeline/index.d.ts +26 -0
- package/dist/lib/db-pipeline/index.js +25 -0
- package/dist/lib/db-pipeline/index.js.map +1 -0
- package/dist/lib/db-pipeline/pipeline.d.ts +13 -0
- package/dist/lib/db-pipeline/pipeline.js +119 -0
- package/dist/lib/db-pipeline/pipeline.js.map +1 -0
- package/dist/lib/db-pipeline/rehearse.d.ts +99 -0
- package/dist/lib/db-pipeline/rehearse.js +219 -0
- package/dist/lib/db-pipeline/rehearse.js.map +1 -0
- package/dist/lib/db-pipeline/types.d.ts +112 -0
- package/dist/lib/db-pipeline/types.js +20 -0
- package/dist/lib/db-pipeline/types.js.map +1 -0
- package/dist/lib/pickers.d.ts +12 -0
- package/dist/lib/pickers.js +34 -0
- package/dist/lib/pickers.js.map +1 -1
- package/package.json +66 -62
- package/templates/auth/callback.ts +22 -22
- package/templates/auth/sign-in.tsx +41 -41
- package/templates/billing/checkout.ts +22 -22
- package/templates/billing/page.tsx +43 -43
- package/templates/support/ticket-form.tsx +68 -68
- package/templates/usage/track.ts +30 -30
- package/templates/users/profile.tsx +43 -43
package/dist/index.js
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import { log } from './utils/logger.js';
|
|
4
4
|
import { CLI_VERSION } from './version.js';
|
|
5
|
+
// pdv #6 fix: fecha stdin antes de qualquer process.exit() para evitar a
|
|
6
|
+
// asserção libuv "!(handle->flags & UV_HANDLE_CLOSING)" no Windows.
|
|
7
|
+
// stdin fica aberto como handle libuv quando inquirer/ora o pegam; destruir
|
|
8
|
+
// antes do exit garante que o loop de eventos drene limpo.
|
|
9
|
+
process.on('exit', () => {
|
|
10
|
+
try {
|
|
11
|
+
process.stdin.destroy();
|
|
12
|
+
}
|
|
13
|
+
catch { /* silencioso — handle pode já estar fechado */ }
|
|
14
|
+
});
|
|
5
15
|
const program = new Command();
|
|
6
16
|
program
|
|
7
17
|
.name('neetru')
|
|
@@ -56,6 +66,7 @@ program
|
|
|
56
66
|
.option('--customer <customerId>', 'customerId dono do workspace (default: self)')
|
|
57
67
|
.option('--skip-init', 'pula o scaffold local')
|
|
58
68
|
.option('--skip-open', 'pula a abertura do browser')
|
|
69
|
+
.option('--skip-db-init', 'pula o 5º passo de inicialização do banco de dados')
|
|
59
70
|
.option('--json', 'saída em JSON (machine-readable)')
|
|
60
71
|
.action(async (name, opts) => {
|
|
61
72
|
const { runNewMacro } = await import('./commands/new.js');
|
|
@@ -66,6 +77,7 @@ program
|
|
|
66
77
|
customer: opts.customer,
|
|
67
78
|
skipInit: !!opts.skipInit,
|
|
68
79
|
skipOpen: !!opts.skipOpen,
|
|
80
|
+
skipDbInit: !!opts.skipDbInit,
|
|
69
81
|
json: !!opts.json,
|
|
70
82
|
});
|
|
71
83
|
});
|
|
@@ -150,6 +162,19 @@ program
|
|
|
150
162
|
const { runWhoami } = await import('./commands/whoami.js');
|
|
151
163
|
await runWhoami({ json: !!opts.json });
|
|
152
164
|
});
|
|
165
|
+
// ── neetru dev ────────────────────────────────────────────────────────
|
|
166
|
+
// Banco local Docker + watch de schema (M1 GAP-M1-4).
|
|
167
|
+
// "salvar = aplicado" — cada save no schema roda o pipeline neetru db apply
|
|
168
|
+
// contra o banco dev-local do produto.
|
|
169
|
+
program
|
|
170
|
+
.command('dev')
|
|
171
|
+
.description('Rodar banco Docker local + watch de schema (dev-local)')
|
|
172
|
+
.option('--db <name>', 'banco alvo do .neetru/db.json (default: único registrado)')
|
|
173
|
+
.option('--schema <path>', 'caminho do arquivo de schema (default: db/schema.ts)')
|
|
174
|
+
.action(async (opts) => {
|
|
175
|
+
const { runDev } = await import('./commands/dev.js');
|
|
176
|
+
await runDev({ db: opts.db, schema: opts.schema });
|
|
177
|
+
});
|
|
153
178
|
// ── neetru build ──────────────────────────────────────────────────────
|
|
154
179
|
program
|
|
155
180
|
.command('build')
|
|
@@ -189,6 +214,7 @@ program
|
|
|
189
214
|
.option('--env <env>', 'ambiente alvo: dev | staging | prod', 'dev')
|
|
190
215
|
.option('--local-artifact', 'F-11: NÃO faz upload pra GCS — manda file:// pro Core (só funciona se o agent compartilha FS com este CLI)')
|
|
191
216
|
.option('--non-interactive', 'falha em vez de perguntar (modo CI)')
|
|
217
|
+
.option('--force', 'ignora o gate de schema e prossegue mesmo com divergência de fingerprint')
|
|
192
218
|
.action(async (opts) => {
|
|
193
219
|
const { runDeploy } = await import('./commands/deploy.js');
|
|
194
220
|
await runDeploy({
|
|
@@ -208,6 +234,7 @@ program
|
|
|
208
234
|
env: opts.env,
|
|
209
235
|
localArtifact: !!opts.localArtifact,
|
|
210
236
|
nonInteractive: !!opts.nonInteractive,
|
|
237
|
+
force: !!opts.force,
|
|
211
238
|
});
|
|
212
239
|
});
|
|
213
240
|
// ── neetru status ─────────────────────────────────────────────────────
|
|
@@ -222,6 +249,47 @@ program
|
|
|
222
249
|
const { runSurfaceStatus } = await import('./commands/surface-status.js');
|
|
223
250
|
await runSurfaceStatus({ clientId: opts.clientId, json: !!opts.json });
|
|
224
251
|
});
|
|
252
|
+
// ── neetru customers ──────────────────────────────────────────────────
|
|
253
|
+
// pdv #2 fix: operadores podem criar customers pelo CLI sem abrir o painel.
|
|
254
|
+
// Customer = empresa/PJ que paga (CRM comercial).
|
|
255
|
+
// Tenant = instância do produto para esse customer.
|
|
256
|
+
const customersCmd = program
|
|
257
|
+
.command('customers')
|
|
258
|
+
.description('Gerenciar customers (empresa/PJ que paga o serviço Neetru)');
|
|
259
|
+
customersCmd
|
|
260
|
+
.command('list')
|
|
261
|
+
.description('Listar customers')
|
|
262
|
+
.option('--status <status>', 'ativo | em prospecção | suspenso | arquivado')
|
|
263
|
+
.option('--search <texto>', 'busca por nome, email ou CNPJ')
|
|
264
|
+
.option('--json', 'saída em JSON')
|
|
265
|
+
.action(async (opts) => {
|
|
266
|
+
const { runCustomersList } = await import('./commands/customers.js');
|
|
267
|
+
await runCustomersList({ status: opts.status, search: opts.search, json: !!opts.json });
|
|
268
|
+
});
|
|
269
|
+
customersCmd
|
|
270
|
+
.command('get <id>')
|
|
271
|
+
.description('Mostrar detalhes de um customer')
|
|
272
|
+
.option('--json', 'saída em JSON')
|
|
273
|
+
.action(async (id, opts) => {
|
|
274
|
+
const { runCustomersGet } = await import('./commands/customers.js');
|
|
275
|
+
await runCustomersGet(id, { json: !!opts.json });
|
|
276
|
+
});
|
|
277
|
+
customersCmd
|
|
278
|
+
.command('create')
|
|
279
|
+
.description('Criar customer (empresa/PJ) — necessário antes de criar workspace')
|
|
280
|
+
.option('--name <nome>', 'nome do customer (razão social ou nome comercial)')
|
|
281
|
+
.option('--email <email>', 'email de contato')
|
|
282
|
+
.option('--tax-id <cnpj>', 'CNPJ ou CPF (opcional)')
|
|
283
|
+
.option('--json', 'saída em JSON')
|
|
284
|
+
.action(async (opts) => {
|
|
285
|
+
const { runCustomersCreate } = await import('./commands/customers.js');
|
|
286
|
+
await runCustomersCreate({
|
|
287
|
+
name: opts.name,
|
|
288
|
+
email: opts.email,
|
|
289
|
+
taxId: opts.taxId,
|
|
290
|
+
json: !!opts.json,
|
|
291
|
+
});
|
|
292
|
+
});
|
|
225
293
|
// ── neetru tenants ────────────────────────────────────────────────────
|
|
226
294
|
const tenantsCmd = program
|
|
227
295
|
.command('tenants')
|
|
@@ -252,7 +320,10 @@ tenantsCmd
|
|
|
252
320
|
});
|
|
253
321
|
tenantsCmd
|
|
254
322
|
.command('create')
|
|
255
|
-
.description('Criar tenant
|
|
323
|
+
.description('[STAFF-ONLY] Criar tenant sem OAuth client/secret.\n' +
|
|
324
|
+
'DEPRECATED: para uso normal (ambiente completo com OAuth), use:\n' +
|
|
325
|
+
' neetru workspaces create\n' +
|
|
326
|
+
'Este comando permanece para casos staff-only (registro de tenant pré-existente).')
|
|
256
327
|
.option('--name <name>', 'nome do tenant')
|
|
257
328
|
.option('--slug <slug>', 'slug do tenant')
|
|
258
329
|
.option('--customer <customerId>', 'id do customer')
|
|
@@ -433,6 +504,8 @@ workspacesCmd
|
|
|
433
504
|
.option('--env <env>', 'dev | staging | prod (default: dev)')
|
|
434
505
|
.option('--tier <tier>', 'dev | standard | enterprise (default: standard)')
|
|
435
506
|
.option('--name <name>', 'label do workspace')
|
|
507
|
+
.option('--bind-config', 'grava tenantId retornado no neetru.config.json do cwd')
|
|
508
|
+
.option('--force-duplicate', 'cria mesmo que já exista ambiente ativo para produto+env')
|
|
436
509
|
.option('--json', 'saída em JSON')
|
|
437
510
|
.action(async (opts) => {
|
|
438
511
|
const { runWorkspacesCreate } = await import('./commands/workspaces.js');
|
|
@@ -442,6 +515,8 @@ workspacesCmd
|
|
|
442
515
|
env: opts.env,
|
|
443
516
|
tier: opts.tier,
|
|
444
517
|
name: opts.name,
|
|
518
|
+
bindConfig: !!opts.bindConfig,
|
|
519
|
+
forceDuplicate: !!opts.forceDuplicate,
|
|
445
520
|
json: !!opts.json,
|
|
446
521
|
});
|
|
447
522
|
});
|
|
@@ -728,17 +803,23 @@ productsCmd
|
|
|
728
803
|
const { runProductsUnpublish } = await import('./commands/products.js');
|
|
729
804
|
await runProductsUnpublish(slug, { json: !!opts.json });
|
|
730
805
|
});
|
|
731
|
-
// ── neetru
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
806
|
+
// ── neetru admin database (Phase A — plano de controle staff de bancos) ───────
|
|
807
|
+
// D-1: renomeado de `neetru products db` → `neetru admin database`.
|
|
808
|
+
// Alias `neetru products db` emite aviso de remoção.
|
|
809
|
+
// D-2: `status` (que era WRITE nesta árvore) renomeado para `set-status`.
|
|
810
|
+
const adminCmd = program
|
|
811
|
+
.command('admin')
|
|
812
|
+
.description('Comandos de administração do plano de controle staff');
|
|
813
|
+
const adminDatabaseCmd = adminCmd
|
|
814
|
+
.command('database')
|
|
815
|
+
.description('Plano de controle staff — bancos isolados por produto (fleet-wide)');
|
|
816
|
+
adminDatabaseCmd
|
|
736
817
|
.command('list')
|
|
737
|
-
.description('Listar bancos de produtos')
|
|
738
|
-
.option('--product-id <id>', 'ID
|
|
818
|
+
.description('[Staff] Listar bancos de todos os produtos')
|
|
819
|
+
.option('--product-id <id>', 'filtrar por ID de produto')
|
|
739
820
|
.option('--engine <engine>', 'firestore-instance | cloud-sql-postgres | cloud-sql-mysql | vm-postgres-single | vm-postgres-cluster | vm-mysql-single | vm-mysql-cluster')
|
|
740
|
-
.option('--status <status>', '
|
|
741
|
-
.option('--json', '
|
|
821
|
+
.option('--status <status>', 'filtrar por status (ativo, provisionando, falha, arquivado)')
|
|
822
|
+
.option('--json', 'saída em JSON estruturado')
|
|
742
823
|
.action(async (opts) => {
|
|
743
824
|
const { runDbList } = await import('./commands/products-db.js');
|
|
744
825
|
await runDbList({
|
|
@@ -748,25 +829,25 @@ productsDbCmd
|
|
|
748
829
|
json: !!opts.json,
|
|
749
830
|
});
|
|
750
831
|
});
|
|
751
|
-
|
|
832
|
+
adminDatabaseCmd
|
|
752
833
|
.command('engines')
|
|
753
|
-
.description('Listar engines de banco suportados')
|
|
834
|
+
.description('[Staff] Listar engines de banco suportados')
|
|
754
835
|
.option('--json')
|
|
755
836
|
.action(async (opts) => {
|
|
756
837
|
const { runDbEngines } = await import('./commands/products-db.js');
|
|
757
838
|
await runDbEngines({ json: !!opts.json });
|
|
758
839
|
});
|
|
759
|
-
|
|
840
|
+
adminDatabaseCmd
|
|
760
841
|
.command('create')
|
|
761
|
-
.description('
|
|
842
|
+
.description('[Staff] Registrar banco de produto no plano de controle (Phase A)')
|
|
762
843
|
.option('--product-id <id>', 'ID do produto')
|
|
763
|
-
.option('--label <label>', '
|
|
844
|
+
.option('--label <label>', 'nome descritivo do banco')
|
|
764
845
|
.option('--engine <engine>', 'firestore-instance | cloud-sql-postgres | cloud-sql-mysql | vm-postgres-single | vm-postgres-cluster | vm-mysql-single | vm-mysql-cluster')
|
|
765
|
-
.option('--env <env>', '
|
|
766
|
-
.option('--region <region>', '
|
|
846
|
+
.option('--env <env>', 'ambiente: dev-local | staging | production')
|
|
847
|
+
.option('--region <region>', 'região GCP', 'us-central1')
|
|
767
848
|
.option('--server-id <serverId>', 'ID da VM alvo (obrigatório para engines vm-*)')
|
|
768
|
-
.option('--replica-count <n>', '
|
|
769
|
-
.option('--json', '
|
|
849
|
+
.option('--replica-count <n>', 'número de réplicas para engines *-cluster (padrão 2)')
|
|
850
|
+
.option('--json', 'saída em JSON estruturado')
|
|
770
851
|
.action(async (opts) => {
|
|
771
852
|
const { runDbCreate } = await import('./commands/products-db.js');
|
|
772
853
|
await runDbCreate({
|
|
@@ -780,26 +861,132 @@ productsDbCmd
|
|
|
780
861
|
json: !!opts.json,
|
|
781
862
|
});
|
|
782
863
|
});
|
|
864
|
+
adminDatabaseCmd
|
|
865
|
+
.command('get [id]')
|
|
866
|
+
.description('[Staff] Mostrar detalhes de um banco')
|
|
867
|
+
.option('--json')
|
|
868
|
+
.action(async (id, opts) => {
|
|
869
|
+
const { runDbGet } = await import('./commands/products-db.js');
|
|
870
|
+
await runDbGet(id, { json: !!opts.json });
|
|
871
|
+
});
|
|
872
|
+
// gestovendas #12 fix: alias `status` → `get` (skill /neetru documenta como `status`).
|
|
873
|
+
adminDatabaseCmd
|
|
874
|
+
.command('status [id]')
|
|
875
|
+
.description('[Staff] Alias de `get` — mostrar detalhes e status de um banco')
|
|
876
|
+
.option('--json')
|
|
877
|
+
.action(async (id, opts) => {
|
|
878
|
+
const { runDbGet } = await import('./commands/products-db.js');
|
|
879
|
+
await runDbGet(id, { json: !!opts.json });
|
|
880
|
+
});
|
|
881
|
+
// D-2: `set-status` é ESCRITA explícita. `status` era ambíguo com o READ em `neetru db status`.
|
|
882
|
+
adminDatabaseCmd
|
|
883
|
+
.command('set-status [id] [status]')
|
|
884
|
+
.description('[Staff] ESCRITA — forçar status do ciclo de vida de um banco (active/failed/archived/…)')
|
|
885
|
+
.option('--reason <text>', 'motivo da mudança de status')
|
|
886
|
+
.option('--json')
|
|
887
|
+
.action(async (id, status, opts) => {
|
|
888
|
+
const { runDbSetStatus } = await import('./commands/products-db.js');
|
|
889
|
+
await runDbSetStatus(id, status, { reason: opts.reason, json: !!opts.json });
|
|
890
|
+
});
|
|
891
|
+
adminDatabaseCmd
|
|
892
|
+
.command('retry [id]')
|
|
893
|
+
.description('[Staff] Reenfileirar provisionamento de banco com falha')
|
|
894
|
+
.option('--json')
|
|
895
|
+
.action(async (id, opts) => {
|
|
896
|
+
const { runDbRetry } = await import('./commands/products-db.js');
|
|
897
|
+
await runDbRetry(id, { json: !!opts.json });
|
|
898
|
+
});
|
|
899
|
+
adminDatabaseCmd
|
|
900
|
+
.command('rotate [id]')
|
|
901
|
+
.description('[Staff] Rotacionar credenciais do banco')
|
|
902
|
+
.option('--json')
|
|
903
|
+
.action(async (id, opts) => {
|
|
904
|
+
const { runDbRotate } = await import('./commands/products-db.js');
|
|
905
|
+
await runDbRotate(id, { json: !!opts.json });
|
|
906
|
+
});
|
|
907
|
+
adminDatabaseCmd
|
|
908
|
+
.command('delete [id]')
|
|
909
|
+
.description('[Staff] Arquivar banco por soft-delete')
|
|
910
|
+
.option('--json')
|
|
911
|
+
.action(async (id, opts) => {
|
|
912
|
+
const { runDbDelete } = await import('./commands/products-db.js');
|
|
913
|
+
await runDbDelete(id, { json: !!opts.json });
|
|
914
|
+
});
|
|
915
|
+
// ── neetru products db (alias de remoção — D-1) ────────────────────────────
|
|
916
|
+
// Emite aviso informando o novo caminho. Mantém subcomandos funcionais por
|
|
917
|
+
// compatibilidade temporária mas deixa claro que foi renomeado.
|
|
918
|
+
const productsDbCmd = productsCmd
|
|
919
|
+
.command('db')
|
|
920
|
+
.description('[RENOMEADO] Use `neetru admin database`. Este alias emite aviso.')
|
|
921
|
+
.hook('preAction', () => {
|
|
922
|
+
process.stderr.write('\nAviso: `neetru products db` foi renomeado para `neetru admin database`.\n' +
|
|
923
|
+
'Por favor, atualize seus scripts. Este alias será removido em breve.\n\n');
|
|
924
|
+
});
|
|
925
|
+
// gestovendas #2 / pdv #5 fix: alias `list` aceita --product (slug legado) OU
|
|
926
|
+
// --product-id (novo). Se slug recebido, passa como productId para o Core.
|
|
927
|
+
// O Core tenta resolver slug → id server-side (fallback); se o Core não suportar,
|
|
928
|
+
// o operador vê mensagem específica do servidor e não um erro de sintaxe.
|
|
929
|
+
productsDbCmd
|
|
930
|
+
.command('list')
|
|
931
|
+
.description('[RENOMEADO — use: neetru admin database list]')
|
|
932
|
+
.option('--product-id <id>', 'ID do produto (novo)')
|
|
933
|
+
.option('--product <slugOrId>', 'slug ou ID do produto (legado — use --product-id)')
|
|
934
|
+
.option('--engine <engine>')
|
|
935
|
+
.option('--status <status>')
|
|
936
|
+
.option('--json')
|
|
937
|
+
.action(async (opts) => {
|
|
938
|
+
// Tradução de flag: --product (legado) → productId (novo).
|
|
939
|
+
const productId = opts.productId ?? opts.product;
|
|
940
|
+
if (opts.product && !opts.productId) {
|
|
941
|
+
process.stderr.write(`[DEPRECATED] Use --product-id em vez de --product.\n` +
|
|
942
|
+
` Próxima major remove o suporte a --product neste alias.\n`);
|
|
943
|
+
}
|
|
944
|
+
const { runDbList } = await import('./commands/products-db.js');
|
|
945
|
+
await runDbList({ productId, engine: opts.engine, status: opts.status, json: !!opts.json });
|
|
946
|
+
});
|
|
947
|
+
productsDbCmd
|
|
948
|
+
.command('engines')
|
|
949
|
+
.description('[RENOMEADO — use: neetru admin database engines]')
|
|
950
|
+
.option('--json')
|
|
951
|
+
.action(async (opts) => {
|
|
952
|
+
const { runDbEngines } = await import('./commands/products-db.js');
|
|
953
|
+
await runDbEngines({ json: !!opts.json });
|
|
954
|
+
});
|
|
955
|
+
productsDbCmd
|
|
956
|
+
.command('create')
|
|
957
|
+
.description('[RENOMEADO — use: neetru admin database create]')
|
|
958
|
+
.option('--product-id <id>')
|
|
959
|
+
.option('--label <label>')
|
|
960
|
+
.option('--engine <engine>')
|
|
961
|
+
.option('--env <env>')
|
|
962
|
+
.option('--region <region>', '', 'us-central1')
|
|
963
|
+
.option('--server-id <serverId>')
|
|
964
|
+
.option('--replica-count <n>')
|
|
965
|
+
.option('--json')
|
|
966
|
+
.action(async (opts) => {
|
|
967
|
+
const { runDbCreate } = await import('./commands/products-db.js');
|
|
968
|
+
await runDbCreate({ productId: opts.productId, label: opts.label, engine: opts.engine, env: opts.env, region: opts.region, serverId: opts.serverId, replicaCount: opts.replicaCount, json: !!opts.json });
|
|
969
|
+
});
|
|
783
970
|
productsDbCmd
|
|
784
971
|
.command('get [id]')
|
|
785
|
-
.description('
|
|
972
|
+
.description('[RENOMEADO — use: neetru admin database get]')
|
|
786
973
|
.option('--json')
|
|
787
974
|
.action(async (id, opts) => {
|
|
788
975
|
const { runDbGet } = await import('./commands/products-db.js');
|
|
789
976
|
await runDbGet(id, { json: !!opts.json });
|
|
790
977
|
});
|
|
791
978
|
productsDbCmd
|
|
792
|
-
.command('status [id] [status]')
|
|
793
|
-
.description('
|
|
979
|
+
.command('set-status [id] [status]')
|
|
980
|
+
.description('[RENOMEADO — use: neetru admin database set-status]')
|
|
794
981
|
.option('--reason <text>')
|
|
795
982
|
.option('--json')
|
|
796
983
|
.action(async (id, status, opts) => {
|
|
797
|
-
const {
|
|
798
|
-
await
|
|
984
|
+
const { runDbSetStatus } = await import('./commands/products-db.js');
|
|
985
|
+
await runDbSetStatus(id, status, { reason: opts.reason, json: !!opts.json });
|
|
799
986
|
});
|
|
800
987
|
productsDbCmd
|
|
801
988
|
.command('retry [id]')
|
|
802
|
-
.description('
|
|
989
|
+
.description('[RENOMEADO — use: neetru admin database retry]')
|
|
803
990
|
.option('--json')
|
|
804
991
|
.action(async (id, opts) => {
|
|
805
992
|
const { runDbRetry } = await import('./commands/products-db.js');
|
|
@@ -807,7 +994,7 @@ productsDbCmd
|
|
|
807
994
|
});
|
|
808
995
|
productsDbCmd
|
|
809
996
|
.command('rotate [id]')
|
|
810
|
-
.description('
|
|
997
|
+
.description('[RENOMEADO — use: neetru admin database rotate]')
|
|
811
998
|
.option('--json')
|
|
812
999
|
.action(async (id, opts) => {
|
|
813
1000
|
const { runDbRotate } = await import('./commands/products-db.js');
|
|
@@ -815,7 +1002,7 @@ productsDbCmd
|
|
|
815
1002
|
});
|
|
816
1003
|
productsDbCmd
|
|
817
1004
|
.command('delete [id]')
|
|
818
|
-
.description('
|
|
1005
|
+
.description('[RENOMEADO — use: neetru admin database delete]')
|
|
819
1006
|
.option('--json')
|
|
820
1007
|
.action(async (id, opts) => {
|
|
821
1008
|
const { runDbDelete } = await import('./commands/products-db.js');
|
|
@@ -916,6 +1103,74 @@ program
|
|
|
916
1103
|
ctaLabel: opts.ctaLabel,
|
|
917
1104
|
});
|
|
918
1105
|
});
|
|
1106
|
+
// ── neetru marketplace ────────────────────────────────────────────────
|
|
1107
|
+
const marketplaceCmd = program
|
|
1108
|
+
.command('marketplace')
|
|
1109
|
+
.description('Central de artefatos do ecossistema Neetru (skills, SDK, templates)');
|
|
1110
|
+
const marketplaceSkillsCmd = marketplaceCmd
|
|
1111
|
+
.command('skills')
|
|
1112
|
+
.description('Gerenciar Skills do Claude Code');
|
|
1113
|
+
marketplaceSkillsCmd
|
|
1114
|
+
.command('install')
|
|
1115
|
+
.description('Clonar neetru-libs e instalar skills em ~/.claude/skills/')
|
|
1116
|
+
.action(async () => {
|
|
1117
|
+
const { runSkillsInstall } = await import('./commands/marketplace.js');
|
|
1118
|
+
await runSkillsInstall();
|
|
1119
|
+
});
|
|
1120
|
+
marketplaceSkillsCmd
|
|
1121
|
+
.command('update')
|
|
1122
|
+
.description('Atualizar cache neetru-libs (git pull) e re-copiar skills instaladas')
|
|
1123
|
+
.action(async () => {
|
|
1124
|
+
const { runSkillsUpdate } = await import('./commands/marketplace.js');
|
|
1125
|
+
await runSkillsUpdate();
|
|
1126
|
+
});
|
|
1127
|
+
marketplaceSkillsCmd
|
|
1128
|
+
.command('list')
|
|
1129
|
+
.description('Listar skills disponíveis no cache local')
|
|
1130
|
+
.action(async () => {
|
|
1131
|
+
const { runSkillsList } = await import('./commands/marketplace.js');
|
|
1132
|
+
await runSkillsList();
|
|
1133
|
+
});
|
|
1134
|
+
marketplaceSkillsCmd
|
|
1135
|
+
.command('uninstall')
|
|
1136
|
+
.description('Remover skills de ~/.claude/skills/ (pede confirmação)')
|
|
1137
|
+
.option('--yes', 'pular confirmação interativa')
|
|
1138
|
+
.action(async (opts) => {
|
|
1139
|
+
const { runSkillsUninstall } = await import('./commands/marketplace.js');
|
|
1140
|
+
await runSkillsUninstall({ yes: !!opts.yes });
|
|
1141
|
+
});
|
|
1142
|
+
const marketplaceSdkCmd = marketplaceCmd
|
|
1143
|
+
.command('sdk')
|
|
1144
|
+
.description('Gerenciar @neetru/sdk no projeto atual');
|
|
1145
|
+
marketplaceSdkCmd
|
|
1146
|
+
.command('init')
|
|
1147
|
+
.description('Adicionar @neetru/sdk ao package.json e criar src/neetru.ts')
|
|
1148
|
+
.action(async () => {
|
|
1149
|
+
const { runSdkInit } = await import('./commands/marketplace.js');
|
|
1150
|
+
await runSdkInit();
|
|
1151
|
+
});
|
|
1152
|
+
marketplaceSdkCmd
|
|
1153
|
+
.command('templates')
|
|
1154
|
+
.description('Listar templates de feature disponíveis (auth, billing, usage…)')
|
|
1155
|
+
.action(async () => {
|
|
1156
|
+
const { runSdkTemplates } = await import('./commands/marketplace.js');
|
|
1157
|
+
await runSdkTemplates();
|
|
1158
|
+
});
|
|
1159
|
+
marketplaceSdkCmd
|
|
1160
|
+
.command('add <template>')
|
|
1161
|
+
.description('Copiar template de feature pra src/ do projeto atual')
|
|
1162
|
+
.option('--force', 'sobrescrever arquivos existentes')
|
|
1163
|
+
.action(async (template, opts) => {
|
|
1164
|
+
const { runSdkAddTemplate } = await import('./commands/marketplace.js');
|
|
1165
|
+
await runSdkAddTemplate(template, { force: !!opts.force });
|
|
1166
|
+
});
|
|
1167
|
+
marketplaceCmd
|
|
1168
|
+
.command('browse')
|
|
1169
|
+
.description('Abrir https://github.com/Neetru/neetru-libs no browser')
|
|
1170
|
+
.action(async () => {
|
|
1171
|
+
const { runMarketplaceBrowse } = await import('./commands/marketplace.js');
|
|
1172
|
+
await runMarketplaceBrowse();
|
|
1173
|
+
});
|
|
919
1174
|
// ── neetru add ────────────────────────────────────────────────────────
|
|
920
1175
|
program
|
|
921
1176
|
.command('add <feature>')
|
|
@@ -972,33 +1227,144 @@ envCmd
|
|
|
972
1227
|
});
|
|
973
1228
|
});
|
|
974
1229
|
// ── neetru db ─────────────────────────────────────────────────────────
|
|
1230
|
+
// M1 — árvore completa de banco por produto.
|
|
1231
|
+
// Subcomandos novos: list, status, apply, migrations list/confirm.
|
|
1232
|
+
// Subcomandos legados (Sprint 10): init --out, migrate, seed.
|
|
975
1233
|
const dbCmd = program
|
|
976
1234
|
.command('db')
|
|
977
|
-
.description('Gerenciar schema, migrations e
|
|
1235
|
+
.description('Gerenciar schema, migrations e banco isolado do produto');
|
|
1236
|
+
// ── neetru db list ────────────────────────────────────────────────────
|
|
1237
|
+
dbCmd
|
|
1238
|
+
.command('list')
|
|
1239
|
+
.description('Listar bancos do produto (GET /api/cli/v1/db)')
|
|
1240
|
+
.option('--product-id <id>', 'filtrar por ID de produto')
|
|
1241
|
+
.option('--engine <engine>', 'filtrar por engine (cloud-sql-postgres, vm-postgres-single, …)')
|
|
1242
|
+
.option('--status <status>', 'filtrar por status (ativo, provisionando, falha, arquivado)')
|
|
1243
|
+
.option('--json', 'saída em JSON estruturado')
|
|
1244
|
+
.action(async (opts) => {
|
|
1245
|
+
const { runDbList } = await import('./commands/db.js');
|
|
1246
|
+
await runDbList({
|
|
1247
|
+
productId: opts.productId,
|
|
1248
|
+
engine: opts.engine,
|
|
1249
|
+
status: opts.status,
|
|
1250
|
+
json: !!opts.json,
|
|
1251
|
+
});
|
|
1252
|
+
});
|
|
1253
|
+
// ── neetru db status <dbId> ───────────────────────────────────────────
|
|
1254
|
+
dbCmd
|
|
1255
|
+
.command('status <dbId>')
|
|
1256
|
+
.description('Detalhar banco + status de provisionamento/saúde')
|
|
1257
|
+
.option('--json', 'saída em JSON estruturado')
|
|
1258
|
+
.action(async (dbId, opts) => {
|
|
1259
|
+
const { runDbStatus } = await import('./commands/db.js');
|
|
1260
|
+
await runDbStatus(dbId, { json: !!opts.json });
|
|
1261
|
+
});
|
|
1262
|
+
// ── neetru db init ────────────────────────────────────────────────────
|
|
1263
|
+
// D-3: opções legadas --out e --force removidas. db init faz UMA coisa.
|
|
1264
|
+
// D-4: --env aceita dev-local (canônico) ou dev (alias explícito com aviso).
|
|
978
1265
|
dbCmd
|
|
979
1266
|
.command('init')
|
|
980
|
-
.description('
|
|
981
|
-
.option('--
|
|
982
|
-
.option('--
|
|
1267
|
+
.description('Registrar banco no Core + gravar .neetru/db.json + scaffoldar db/schema.ts')
|
|
1268
|
+
.option('--name <name>', 'nome do banco (interativo se ausente)')
|
|
1269
|
+
.option('--engine <engine>', 'engine: cloud-sql-postgres | vm-postgres-single | firestore-instance | …')
|
|
1270
|
+
.option('--env <env>', 'ambiente: dev-local (padrão) | staging | production')
|
|
1271
|
+
.option('--product-id <id>', 'override do productId (default: slug do neetru.config.json)')
|
|
1272
|
+
.option('-y, --yes', 'modo não-interativo (usa defaults)')
|
|
1273
|
+
.option('--json', 'saída em JSON estruturado')
|
|
983
1274
|
.action(async (opts) => {
|
|
984
1275
|
const { runDbInit } = await import('./commands/db.js');
|
|
985
|
-
await runDbInit({
|
|
1276
|
+
await runDbInit({
|
|
1277
|
+
name: opts.name,
|
|
1278
|
+
engine: opts.engine,
|
|
1279
|
+
env: opts.env,
|
|
1280
|
+
productId: opts.productId,
|
|
1281
|
+
yes: !!opts.yes,
|
|
1282
|
+
json: !!opts.json,
|
|
1283
|
+
});
|
|
986
1284
|
});
|
|
1285
|
+
// ── neetru db apply ───────────────────────────────────────────────────
|
|
1286
|
+
// D-4: --env usa dev-local como default canônico.
|
|
987
1287
|
dbCmd
|
|
988
|
-
.command('
|
|
989
|
-
.description('
|
|
990
|
-
.option('--
|
|
991
|
-
.
|
|
992
|
-
|
|
993
|
-
|
|
1288
|
+
.command('apply')
|
|
1289
|
+
.description('Executar pipeline de migração + enviar ao Core (POST /api/cli/v1/db/migrations/push)')
|
|
1290
|
+
.option('--db <name>', 'banco alvo (interativo se mais de um registrado)')
|
|
1291
|
+
.option('--env <env>', 'ambiente alvo: dev-local (padrão) | staging | production')
|
|
1292
|
+
.option('--schema <path>', 'caminho do schema (default: db/schema.ts)')
|
|
1293
|
+
.option('--dry-run', 'calcula o diff mas NÃO envia ao Core')
|
|
1294
|
+
.option('-y, --yes', 'pula a confirmação interativa')
|
|
1295
|
+
.option('--json', 'saída em JSON estruturado')
|
|
1296
|
+
.action(async (opts) => {
|
|
1297
|
+
const { runDbApply } = await import('./commands/db.js');
|
|
1298
|
+
await runDbApply({
|
|
1299
|
+
dbName: opts.db,
|
|
1300
|
+
env: opts.env,
|
|
1301
|
+
schemaPath: opts.schema,
|
|
1302
|
+
dryRun: !!opts.dryRun,
|
|
1303
|
+
yes: !!opts.yes,
|
|
1304
|
+
json: !!opts.json,
|
|
1305
|
+
});
|
|
1306
|
+
});
|
|
1307
|
+
// ── neetru db migrations ──────────────────────────────────────────────
|
|
1308
|
+
const dbMigrationsCmd = dbCmd
|
|
1309
|
+
.command('migrations')
|
|
1310
|
+
.description('Operar migrações de banco');
|
|
1311
|
+
dbMigrationsCmd
|
|
1312
|
+
.command('list')
|
|
1313
|
+
.description('Listar migrações registradas (GET /api/cli/v1/db/migrations)')
|
|
1314
|
+
.option('--db <dbId>', 'filtrar por ID do banco')
|
|
1315
|
+
.option('--json', 'saída em JSON estruturado')
|
|
1316
|
+
.action(async (opts) => {
|
|
1317
|
+
const { runDbMigrationsList } = await import('./commands/db.js');
|
|
1318
|
+
await runDbMigrationsList({ dbId: opts.db, json: !!opts.json });
|
|
994
1319
|
});
|
|
1320
|
+
dbMigrationsCmd
|
|
1321
|
+
.command('confirm <migrationId>')
|
|
1322
|
+
.description('Confirmar migração destrutiva (POST /api/cli/v1/db/migrations/[id]/confirm — exige MFA)')
|
|
1323
|
+
.requiredOption('--mfa <token>', 'código TOTP step-up MFA')
|
|
1324
|
+
.option('--json', 'saída em JSON')
|
|
1325
|
+
.action(async (migrationId, opts) => {
|
|
1326
|
+
const { runDbMigrationsConfirm } = await import('./commands/db.js');
|
|
1327
|
+
await runDbMigrationsConfirm(migrationId, { mfa: opts.mfa, json: !!opts.json });
|
|
1328
|
+
});
|
|
1329
|
+
// D-3: neetru db migrate removido (legado Sprint 10 cortado).
|
|
1330
|
+
// ── neetru db backups <dbId> ──────────────────────────────────────────
|
|
1331
|
+
dbCmd
|
|
1332
|
+
.command('backups <dbId>')
|
|
1333
|
+
.description('Listar backups de um banco (GET /api/cli/v1/db/[id]/backups)')
|
|
1334
|
+
.option('--json', 'saída em JSON estruturado')
|
|
1335
|
+
.action(async (dbId, opts) => {
|
|
1336
|
+
const { runDbBackups } = await import('./commands/db.js');
|
|
1337
|
+
await runDbBackups(dbId, { json: !!opts.json });
|
|
1338
|
+
});
|
|
1339
|
+
// ── neetru db restore <dbId> ──────────────────────────────────────────
|
|
1340
|
+
dbCmd
|
|
1341
|
+
.command('restore <dbId>')
|
|
1342
|
+
.description('Restaurar banco a partir de backup (POST /api/cli/v1/db/[id]/restore — exige MFA)')
|
|
1343
|
+
.requiredOption('--mfa <token>', 'código TOTP step-up MFA (obrigatório — operação destrutiva)')
|
|
1344
|
+
.option('--json', 'saída em JSON')
|
|
1345
|
+
.action(async (dbId, opts) => {
|
|
1346
|
+
const { runDbRestore } = await import('./commands/db.js');
|
|
1347
|
+
await runDbRestore(dbId, { mfa: opts.mfa, json: !!opts.json });
|
|
1348
|
+
});
|
|
1349
|
+
// ── neetru db hosts ───────────────────────────────────────────────────
|
|
1350
|
+
// Alias: também acessível via `neetru db-hosts` (top-level).
|
|
995
1351
|
dbCmd
|
|
996
|
-
.command('
|
|
997
|
-
.description('
|
|
998
|
-
.option('--
|
|
1352
|
+
.command('hosts')
|
|
1353
|
+
.description('Listar VM hosts de banco e densidade (GET /api/cli/v1/servers?capacity=true&db=true)')
|
|
1354
|
+
.option('--json', 'saída em JSON estruturado')
|
|
999
1355
|
.action(async (opts) => {
|
|
1000
|
-
const {
|
|
1001
|
-
await
|
|
1356
|
+
const { runDbHosts } = await import('./commands/db.js');
|
|
1357
|
+
await runDbHosts({ json: !!opts.json });
|
|
1358
|
+
});
|
|
1359
|
+
// D-3: neetru db seed removido (legado Sprint 10 cortado).
|
|
1360
|
+
// ── neetru db-hosts (top-level alias de `neetru db hosts`) ───────────
|
|
1361
|
+
program
|
|
1362
|
+
.command('db-hosts')
|
|
1363
|
+
.description('Listar VM hosts de banco e densidade (alias de `neetru db hosts`)')
|
|
1364
|
+
.option('--json', 'saída em JSON estruturado')
|
|
1365
|
+
.action(async (opts) => {
|
|
1366
|
+
const { runDbHosts } = await import('./commands/db.js');
|
|
1367
|
+
await runDbHosts({ json: !!opts.json });
|
|
1002
1368
|
});
|
|
1003
1369
|
// ── neetru fn ─────────────────────────────────────────────────────────
|
|
1004
1370
|
const fnCmd = program
|
|
@@ -1220,6 +1586,117 @@ supportTicketsCmd
|
|
|
1220
1586
|
const { runSupportTicketsStatus } = await import('./commands/support.js');
|
|
1221
1587
|
await runSupportTicketsStatus(id, { to: opts.to, json: !!opts.json });
|
|
1222
1588
|
});
|
|
1589
|
+
// ── neetru bug ───────────────────────────────────────────────────────
|
|
1590
|
+
/**
|
|
1591
|
+
* neetru bug — bugs e ocorrências reportados pela CLI, agentes Claude e staff.
|
|
1592
|
+
*
|
|
1593
|
+
* Subcomandos:
|
|
1594
|
+
* report — reportar novo bug (interativo ou one-shot via flags)
|
|
1595
|
+
* list — listar bugs abertos (ou com filtros)
|
|
1596
|
+
* show <id> — detalhe completo
|
|
1597
|
+
* claim <id> — assumir investigação
|
|
1598
|
+
* resolve <id> — encerrar (resolved/wont_fix/duplicate)
|
|
1599
|
+
* comment <id> — adicionar comentário na thread
|
|
1600
|
+
*
|
|
1601
|
+
* Exemplo rápido (agentes Claude):
|
|
1602
|
+
* neetru bug report --title "X trava" --body "Stack trace…" --category cli --severity high --actor-type agent_claude --json
|
|
1603
|
+
* neetru bug list --status open --json
|
|
1604
|
+
*/
|
|
1605
|
+
const bugCmd = program
|
|
1606
|
+
.command('bug')
|
|
1607
|
+
.description('Reportar, listar e resolver bugs e ocorrências da plataforma');
|
|
1608
|
+
bugCmd
|
|
1609
|
+
.command('report')
|
|
1610
|
+
.description('Reportar novo bug (interativo ou flags --title/--body para agentes)')
|
|
1611
|
+
.option('--title <text>', 'título curto do bug')
|
|
1612
|
+
.option('--body <text>', 'descrição detalhada')
|
|
1613
|
+
.option('--category <cat>', 'cli | sdk | core | agent | libs | docs | infra | other', 'other')
|
|
1614
|
+
.option('--severity <sev>', 'critical | high | medium | low', 'medium')
|
|
1615
|
+
.option('--product <id>', 'productId afetado (opcional)')
|
|
1616
|
+
.option('--steps <text>', 'passos para reproduzir (opcional)')
|
|
1617
|
+
.option('--expected <text>', 'comportamento esperado (opcional)')
|
|
1618
|
+
.option('--actual <text>', 'comportamento atual (opcional)')
|
|
1619
|
+
.option('--actor-type <type>', 'cli_principal | agent_claude | staff_session', 'cli_principal')
|
|
1620
|
+
.option('--json', 'saída em JSON (modo não-interativo)')
|
|
1621
|
+
.action(async (opts) => {
|
|
1622
|
+
const { runBugReport } = await import('./commands/bug.js');
|
|
1623
|
+
await runBugReport({
|
|
1624
|
+
title: opts.title,
|
|
1625
|
+
body: opts.body,
|
|
1626
|
+
category: opts.category,
|
|
1627
|
+
severity: opts.severity,
|
|
1628
|
+
product: opts.product,
|
|
1629
|
+
steps: opts.steps,
|
|
1630
|
+
expected: opts.expected,
|
|
1631
|
+
actual: opts.actual,
|
|
1632
|
+
actorType: opts.actorType,
|
|
1633
|
+
json: !!opts.json,
|
|
1634
|
+
});
|
|
1635
|
+
});
|
|
1636
|
+
bugCmd
|
|
1637
|
+
.command('list')
|
|
1638
|
+
.description('Listar bugs e ocorrências')
|
|
1639
|
+
.option('--status <s>', 'open | triaged | in_progress | resolved | wont_fix | duplicate')
|
|
1640
|
+
.option('--category <cat>', 'cli | sdk | core | agent | libs | docs | infra | other')
|
|
1641
|
+
.option('--assigned-to <uid>', 'filtrar por responsável (uid ou session id)')
|
|
1642
|
+
.option('--product <id>', 'filtrar por productId')
|
|
1643
|
+
.option('--limit <n>', 'máximo de resultados (default 20, max 200)')
|
|
1644
|
+
.option('--json', 'saída em JSON')
|
|
1645
|
+
.action(async (opts) => {
|
|
1646
|
+
const { runBugList } = await import('./commands/bug.js');
|
|
1647
|
+
await runBugList({
|
|
1648
|
+
status: opts.status,
|
|
1649
|
+
category: opts.category,
|
|
1650
|
+
assignedTo: opts.assignedTo,
|
|
1651
|
+
product: opts.product,
|
|
1652
|
+
limit: opts.limit,
|
|
1653
|
+
json: !!opts.json,
|
|
1654
|
+
});
|
|
1655
|
+
});
|
|
1656
|
+
bugCmd
|
|
1657
|
+
.command('show <id>')
|
|
1658
|
+
.description('Mostrar detalhe completo de um bug')
|
|
1659
|
+
.option('--json', 'saída em JSON')
|
|
1660
|
+
.action(async (id, opts) => {
|
|
1661
|
+
const { runBugShow } = await import('./commands/bug.js');
|
|
1662
|
+
await runBugShow(id, { json: !!opts.json });
|
|
1663
|
+
});
|
|
1664
|
+
bugCmd
|
|
1665
|
+
.command('claim <id>')
|
|
1666
|
+
.description('Assumir investigação de um bug')
|
|
1667
|
+
.option('--assigned-to <uid>', 'uid ou session id (default: caller)')
|
|
1668
|
+
.option('--json', 'saída em JSON')
|
|
1669
|
+
.action(async (id, opts) => {
|
|
1670
|
+
const { runBugClaim } = await import('./commands/bug.js');
|
|
1671
|
+
await runBugClaim(id, { assignedTo: opts.assignedTo, json: !!opts.json });
|
|
1672
|
+
});
|
|
1673
|
+
bugCmd
|
|
1674
|
+
.command('resolve <id>')
|
|
1675
|
+
.description('Encerrar um bug como resolvido, wont_fix ou duplicate')
|
|
1676
|
+
.option('--summary <text>', 'resumo do que foi feito / por que não corrigir')
|
|
1677
|
+
.option('--commit <sha>', 'commit SHA que corrige o bug (opcional)')
|
|
1678
|
+
.option('--status <s>', 'resolved | wont_fix | duplicate (default: resolved)', 'resolved')
|
|
1679
|
+
.option('--duplicate-of <id>', 'ID do bug original (obrigatório quando --status duplicate)')
|
|
1680
|
+
.option('--json', 'saída em JSON (modo não-interativo)')
|
|
1681
|
+
.action(async (id, opts) => {
|
|
1682
|
+
const { runBugResolve } = await import('./commands/bug.js');
|
|
1683
|
+
await runBugResolve(id, {
|
|
1684
|
+
summary: opts.summary,
|
|
1685
|
+
commit: opts.commit,
|
|
1686
|
+
status: opts.status,
|
|
1687
|
+
duplicateOf: opts.duplicateOf,
|
|
1688
|
+
json: !!opts.json,
|
|
1689
|
+
});
|
|
1690
|
+
});
|
|
1691
|
+
bugCmd
|
|
1692
|
+
.command('comment <id>')
|
|
1693
|
+
.description('Adicionar comentário na thread de um bug')
|
|
1694
|
+
.option('--body <text>', 'corpo do comentário')
|
|
1695
|
+
.option('--json', 'saída em JSON (modo não-interativo)')
|
|
1696
|
+
.action(async (id, opts) => {
|
|
1697
|
+
const { runBugComment } = await import('./commands/bug.js');
|
|
1698
|
+
await runBugComment(id, { body: opts.body, json: !!opts.json });
|
|
1699
|
+
});
|
|
1223
1700
|
// ── neetru dns ───────────────────────────────────────────────────────
|
|
1224
1701
|
const dnsCmd = program
|
|
1225
1702
|
.command('dns')
|
|
@@ -1356,9 +1833,20 @@ drCmd
|
|
|
1356
1833
|
// Frente B — docs em GCS + Firestore registry. Desacopla conteúdo de docs
|
|
1357
1834
|
// do deploy do Core (owner edita markdown direto pelo bucket OU via CLI,
|
|
1358
1835
|
// sem rebuild).
|
|
1836
|
+
//
|
|
1837
|
+
// `neetru docs open [topic]` abre documentação no browser. É o ponto de
|
|
1838
|
+
// entrada pra quem quer LER docs, não publicar.
|
|
1359
1839
|
const docsCmd = program
|
|
1360
1840
|
.command('docs')
|
|
1361
|
-
.description('
|
|
1841
|
+
.description('Documentação + registry de docs publicados em gs://neetru-docs');
|
|
1842
|
+
docsCmd
|
|
1843
|
+
.command('open [topic]')
|
|
1844
|
+
.description('Abrir documentação no browser (ex: sdk, cli, db, webhooks, auth)')
|
|
1845
|
+
.option('--json', 'saída em JSON (imprime URL sem abrir browser)')
|
|
1846
|
+
.action(async (topic, opts) => {
|
|
1847
|
+
const { runDocsOpen } = await import('./commands/docs.js');
|
|
1848
|
+
await runDocsOpen(topic, { json: !!opts.json });
|
|
1849
|
+
});
|
|
1362
1850
|
docsCmd
|
|
1363
1851
|
.command('publish <file>')
|
|
1364
1852
|
.description('Publicar arquivo markdown (sobe pro GCS + registry Firestore)')
|