@neetru/cli 2.7.4 → 2.8.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/CHANGELOG.md +220 -208
- 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/db.d.ts +87 -7
- package/dist/commands/db.js +697 -126
- 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/init.js +121 -121
- package/dist/commands/new.d.ts +6 -0
- package/dist/commands/new.js +31 -10
- package/dist/commands/new.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/upgrade.js +5 -2
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/index.js +258 -42
- package/dist/index.js.map +1 -1
- package/dist/lib/ai/context.js +90 -90
- 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/package.json +63 -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
|
@@ -56,6 +56,7 @@ program
|
|
|
56
56
|
.option('--customer <customerId>', 'customerId dono do workspace (default: self)')
|
|
57
57
|
.option('--skip-init', 'pula o scaffold local')
|
|
58
58
|
.option('--skip-open', 'pula a abertura do browser')
|
|
59
|
+
.option('--skip-db-init', 'pula o 5º passo de inicialização do banco de dados')
|
|
59
60
|
.option('--json', 'saída em JSON (machine-readable)')
|
|
60
61
|
.action(async (name, opts) => {
|
|
61
62
|
const { runNewMacro } = await import('./commands/new.js');
|
|
@@ -66,6 +67,7 @@ program
|
|
|
66
67
|
customer: opts.customer,
|
|
67
68
|
skipInit: !!opts.skipInit,
|
|
68
69
|
skipOpen: !!opts.skipOpen,
|
|
70
|
+
skipDbInit: !!opts.skipDbInit,
|
|
69
71
|
json: !!opts.json,
|
|
70
72
|
});
|
|
71
73
|
});
|
|
@@ -150,6 +152,19 @@ program
|
|
|
150
152
|
const { runWhoami } = await import('./commands/whoami.js');
|
|
151
153
|
await runWhoami({ json: !!opts.json });
|
|
152
154
|
});
|
|
155
|
+
// ── neetru dev ────────────────────────────────────────────────────────
|
|
156
|
+
// Banco local Docker + watch de schema (M1 GAP-M1-4).
|
|
157
|
+
// "salvar = aplicado" — cada save no schema roda o pipeline neetru db apply
|
|
158
|
+
// contra o banco dev-local do produto.
|
|
159
|
+
program
|
|
160
|
+
.command('dev')
|
|
161
|
+
.description('Rodar banco Docker local + watch de schema (dev-local)')
|
|
162
|
+
.option('--db <name>', 'banco alvo do .neetru/db.json (default: único registrado)')
|
|
163
|
+
.option('--schema <path>', 'caminho do arquivo de schema (default: db/schema.ts)')
|
|
164
|
+
.action(async (opts) => {
|
|
165
|
+
const { runDev } = await import('./commands/dev.js');
|
|
166
|
+
await runDev({ db: opts.db, schema: opts.schema });
|
|
167
|
+
});
|
|
153
168
|
// ── neetru build ──────────────────────────────────────────────────────
|
|
154
169
|
program
|
|
155
170
|
.command('build')
|
|
@@ -189,6 +204,7 @@ program
|
|
|
189
204
|
.option('--env <env>', 'ambiente alvo: dev | staging | prod', 'dev')
|
|
190
205
|
.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
206
|
.option('--non-interactive', 'falha em vez de perguntar (modo CI)')
|
|
207
|
+
.option('--force', 'ignora o gate de schema e prossegue mesmo com divergência de fingerprint')
|
|
192
208
|
.action(async (opts) => {
|
|
193
209
|
const { runDeploy } = await import('./commands/deploy.js');
|
|
194
210
|
await runDeploy({
|
|
@@ -208,6 +224,7 @@ program
|
|
|
208
224
|
env: opts.env,
|
|
209
225
|
localArtifact: !!opts.localArtifact,
|
|
210
226
|
nonInteractive: !!opts.nonInteractive,
|
|
227
|
+
force: !!opts.force,
|
|
211
228
|
});
|
|
212
229
|
});
|
|
213
230
|
// ── neetru status ─────────────────────────────────────────────────────
|
|
@@ -728,17 +745,23 @@ productsCmd
|
|
|
728
745
|
const { runProductsUnpublish } = await import('./commands/products.js');
|
|
729
746
|
await runProductsUnpublish(slug, { json: !!opts.json });
|
|
730
747
|
});
|
|
731
|
-
// ── neetru
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
748
|
+
// ── neetru admin database (Phase A — plano de controle staff de bancos) ───────
|
|
749
|
+
// D-1: renomeado de `neetru products db` → `neetru admin database`.
|
|
750
|
+
// Alias `neetru products db` emite aviso de remoção.
|
|
751
|
+
// D-2: `status` (que era WRITE nesta árvore) renomeado para `set-status`.
|
|
752
|
+
const adminCmd = program
|
|
753
|
+
.command('admin')
|
|
754
|
+
.description('Comandos de administração do plano de controle staff');
|
|
755
|
+
const adminDatabaseCmd = adminCmd
|
|
756
|
+
.command('database')
|
|
757
|
+
.description('Plano de controle staff — bancos isolados por produto (fleet-wide)');
|
|
758
|
+
adminDatabaseCmd
|
|
736
759
|
.command('list')
|
|
737
|
-
.description('Listar bancos de produtos')
|
|
738
|
-
.option('--product-id <id>', 'ID
|
|
760
|
+
.description('[Staff] Listar bancos de todos os produtos')
|
|
761
|
+
.option('--product-id <id>', 'filtrar por ID de produto')
|
|
739
762
|
.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', '
|
|
763
|
+
.option('--status <status>', 'filtrar por status (ativo, provisionando, falha, arquivado)')
|
|
764
|
+
.option('--json', 'saída em JSON estruturado')
|
|
742
765
|
.action(async (opts) => {
|
|
743
766
|
const { runDbList } = await import('./commands/products-db.js');
|
|
744
767
|
await runDbList({
|
|
@@ -748,25 +771,25 @@ productsDbCmd
|
|
|
748
771
|
json: !!opts.json,
|
|
749
772
|
});
|
|
750
773
|
});
|
|
751
|
-
|
|
774
|
+
adminDatabaseCmd
|
|
752
775
|
.command('engines')
|
|
753
|
-
.description('Listar engines de banco suportados')
|
|
776
|
+
.description('[Staff] Listar engines de banco suportados')
|
|
754
777
|
.option('--json')
|
|
755
778
|
.action(async (opts) => {
|
|
756
779
|
const { runDbEngines } = await import('./commands/products-db.js');
|
|
757
780
|
await runDbEngines({ json: !!opts.json });
|
|
758
781
|
});
|
|
759
|
-
|
|
782
|
+
adminDatabaseCmd
|
|
760
783
|
.command('create')
|
|
761
|
-
.description('
|
|
784
|
+
.description('[Staff] Registrar banco de produto no plano de controle (Phase A)')
|
|
762
785
|
.option('--product-id <id>', 'ID do produto')
|
|
763
|
-
.option('--label <label>', '
|
|
786
|
+
.option('--label <label>', 'nome descritivo do banco')
|
|
764
787
|
.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>', '
|
|
788
|
+
.option('--env <env>', 'ambiente: dev-local | staging | production')
|
|
789
|
+
.option('--region <region>', 'região GCP', 'us-central1')
|
|
767
790
|
.option('--server-id <serverId>', 'ID da VM alvo (obrigatório para engines vm-*)')
|
|
768
|
-
.option('--replica-count <n>', '
|
|
769
|
-
.option('--json', '
|
|
791
|
+
.option('--replica-count <n>', 'número de réplicas para engines *-cluster (padrão 2)')
|
|
792
|
+
.option('--json', 'saída em JSON estruturado')
|
|
770
793
|
.action(async (opts) => {
|
|
771
794
|
const { runDbCreate } = await import('./commands/products-db.js');
|
|
772
795
|
await runDbCreate({
|
|
@@ -780,26 +803,112 @@ productsDbCmd
|
|
|
780
803
|
json: !!opts.json,
|
|
781
804
|
});
|
|
782
805
|
});
|
|
806
|
+
adminDatabaseCmd
|
|
807
|
+
.command('get [id]')
|
|
808
|
+
.description('[Staff] Mostrar detalhes de um banco')
|
|
809
|
+
.option('--json')
|
|
810
|
+
.action(async (id, opts) => {
|
|
811
|
+
const { runDbGet } = await import('./commands/products-db.js');
|
|
812
|
+
await runDbGet(id, { json: !!opts.json });
|
|
813
|
+
});
|
|
814
|
+
// D-2: `set-status` é ESCRITA explícita. `status` era ambíguo com o READ em `neetru db status`.
|
|
815
|
+
adminDatabaseCmd
|
|
816
|
+
.command('set-status [id] [status]')
|
|
817
|
+
.description('[Staff] ESCRITA — forçar status do ciclo de vida de um banco (active/failed/archived/…)')
|
|
818
|
+
.option('--reason <text>', 'motivo da mudança de status')
|
|
819
|
+
.option('--json')
|
|
820
|
+
.action(async (id, status, opts) => {
|
|
821
|
+
const { runDbSetStatus } = await import('./commands/products-db.js');
|
|
822
|
+
await runDbSetStatus(id, status, { reason: opts.reason, json: !!opts.json });
|
|
823
|
+
});
|
|
824
|
+
adminDatabaseCmd
|
|
825
|
+
.command('retry [id]')
|
|
826
|
+
.description('[Staff] Reenfileirar provisionamento de banco com falha')
|
|
827
|
+
.option('--json')
|
|
828
|
+
.action(async (id, opts) => {
|
|
829
|
+
const { runDbRetry } = await import('./commands/products-db.js');
|
|
830
|
+
await runDbRetry(id, { json: !!opts.json });
|
|
831
|
+
});
|
|
832
|
+
adminDatabaseCmd
|
|
833
|
+
.command('rotate [id]')
|
|
834
|
+
.description('[Staff] Rotacionar credenciais do banco')
|
|
835
|
+
.option('--json')
|
|
836
|
+
.action(async (id, opts) => {
|
|
837
|
+
const { runDbRotate } = await import('./commands/products-db.js');
|
|
838
|
+
await runDbRotate(id, { json: !!opts.json });
|
|
839
|
+
});
|
|
840
|
+
adminDatabaseCmd
|
|
841
|
+
.command('delete [id]')
|
|
842
|
+
.description('[Staff] Arquivar banco por soft-delete')
|
|
843
|
+
.option('--json')
|
|
844
|
+
.action(async (id, opts) => {
|
|
845
|
+
const { runDbDelete } = await import('./commands/products-db.js');
|
|
846
|
+
await runDbDelete(id, { json: !!opts.json });
|
|
847
|
+
});
|
|
848
|
+
// ── neetru products db (alias de remoção — D-1) ────────────────────────────
|
|
849
|
+
// Emite aviso informando o novo caminho. Mantém subcomandos funcionais por
|
|
850
|
+
// compatibilidade temporária mas deixa claro que foi renomeado.
|
|
851
|
+
const productsDbCmd = productsCmd
|
|
852
|
+
.command('db')
|
|
853
|
+
.description('[RENOMEADO] Use `neetru admin database`. Este alias emite aviso.')
|
|
854
|
+
.hook('preAction', () => {
|
|
855
|
+
process.stderr.write('\nAviso: `neetru products db` foi renomeado para `neetru admin database`.\n' +
|
|
856
|
+
'Por favor, atualize seus scripts. Este alias será removido em breve.\n\n');
|
|
857
|
+
});
|
|
858
|
+
productsDbCmd
|
|
859
|
+
.command('list')
|
|
860
|
+
.description('[RENOMEADO — use: neetru admin database list]')
|
|
861
|
+
.option('--product-id <id>')
|
|
862
|
+
.option('--engine <engine>')
|
|
863
|
+
.option('--status <status>')
|
|
864
|
+
.option('--json')
|
|
865
|
+
.action(async (opts) => {
|
|
866
|
+
const { runDbList } = await import('./commands/products-db.js');
|
|
867
|
+
await runDbList({ productId: opts.productId, engine: opts.engine, status: opts.status, json: !!opts.json });
|
|
868
|
+
});
|
|
869
|
+
productsDbCmd
|
|
870
|
+
.command('engines')
|
|
871
|
+
.description('[RENOMEADO — use: neetru admin database engines]')
|
|
872
|
+
.option('--json')
|
|
873
|
+
.action(async (opts) => {
|
|
874
|
+
const { runDbEngines } = await import('./commands/products-db.js');
|
|
875
|
+
await runDbEngines({ json: !!opts.json });
|
|
876
|
+
});
|
|
877
|
+
productsDbCmd
|
|
878
|
+
.command('create')
|
|
879
|
+
.description('[RENOMEADO — use: neetru admin database create]')
|
|
880
|
+
.option('--product-id <id>')
|
|
881
|
+
.option('--label <label>')
|
|
882
|
+
.option('--engine <engine>')
|
|
883
|
+
.option('--env <env>')
|
|
884
|
+
.option('--region <region>', '', 'us-central1')
|
|
885
|
+
.option('--server-id <serverId>')
|
|
886
|
+
.option('--replica-count <n>')
|
|
887
|
+
.option('--json')
|
|
888
|
+
.action(async (opts) => {
|
|
889
|
+
const { runDbCreate } = await import('./commands/products-db.js');
|
|
890
|
+
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 });
|
|
891
|
+
});
|
|
783
892
|
productsDbCmd
|
|
784
893
|
.command('get [id]')
|
|
785
|
-
.description('
|
|
894
|
+
.description('[RENOMEADO — use: neetru admin database get]')
|
|
786
895
|
.option('--json')
|
|
787
896
|
.action(async (id, opts) => {
|
|
788
897
|
const { runDbGet } = await import('./commands/products-db.js');
|
|
789
898
|
await runDbGet(id, { json: !!opts.json });
|
|
790
899
|
});
|
|
791
900
|
productsDbCmd
|
|
792
|
-
.command('status [id] [status]')
|
|
793
|
-
.description('
|
|
901
|
+
.command('set-status [id] [status]')
|
|
902
|
+
.description('[RENOMEADO — use: neetru admin database set-status]')
|
|
794
903
|
.option('--reason <text>')
|
|
795
904
|
.option('--json')
|
|
796
905
|
.action(async (id, status, opts) => {
|
|
797
|
-
const {
|
|
798
|
-
await
|
|
906
|
+
const { runDbSetStatus } = await import('./commands/products-db.js');
|
|
907
|
+
await runDbSetStatus(id, status, { reason: opts.reason, json: !!opts.json });
|
|
799
908
|
});
|
|
800
909
|
productsDbCmd
|
|
801
910
|
.command('retry [id]')
|
|
802
|
-
.description('
|
|
911
|
+
.description('[RENOMEADO — use: neetru admin database retry]')
|
|
803
912
|
.option('--json')
|
|
804
913
|
.action(async (id, opts) => {
|
|
805
914
|
const { runDbRetry } = await import('./commands/products-db.js');
|
|
@@ -807,7 +916,7 @@ productsDbCmd
|
|
|
807
916
|
});
|
|
808
917
|
productsDbCmd
|
|
809
918
|
.command('rotate [id]')
|
|
810
|
-
.description('
|
|
919
|
+
.description('[RENOMEADO — use: neetru admin database rotate]')
|
|
811
920
|
.option('--json')
|
|
812
921
|
.action(async (id, opts) => {
|
|
813
922
|
const { runDbRotate } = await import('./commands/products-db.js');
|
|
@@ -815,7 +924,7 @@ productsDbCmd
|
|
|
815
924
|
});
|
|
816
925
|
productsDbCmd
|
|
817
926
|
.command('delete [id]')
|
|
818
|
-
.description('
|
|
927
|
+
.description('[RENOMEADO — use: neetru admin database delete]')
|
|
819
928
|
.option('--json')
|
|
820
929
|
.action(async (id, opts) => {
|
|
821
930
|
const { runDbDelete } = await import('./commands/products-db.js');
|
|
@@ -972,33 +1081,140 @@ envCmd
|
|
|
972
1081
|
});
|
|
973
1082
|
});
|
|
974
1083
|
// ── neetru db ─────────────────────────────────────────────────────────
|
|
1084
|
+
// M1 — árvore completa de banco por produto.
|
|
1085
|
+
// Subcomandos novos: list, status, apply, migrations list/confirm.
|
|
1086
|
+
// Subcomandos legados (Sprint 10): init --out, migrate, seed.
|
|
975
1087
|
const dbCmd = program
|
|
976
1088
|
.command('db')
|
|
977
|
-
.description('Gerenciar schema, migrations e
|
|
1089
|
+
.description('Gerenciar schema, migrations e banco isolado do produto');
|
|
1090
|
+
// ── neetru db list ────────────────────────────────────────────────────
|
|
1091
|
+
dbCmd
|
|
1092
|
+
.command('list')
|
|
1093
|
+
.description('Listar bancos do produto (GET /api/cli/v1/db)')
|
|
1094
|
+
.option('--product-id <id>', 'filtrar por ID de produto')
|
|
1095
|
+
.option('--engine <engine>', 'filtrar por engine (cloud-sql-postgres, vm-postgres-single, …)')
|
|
1096
|
+
.option('--status <status>', 'filtrar por status (ativo, provisionando, falha, arquivado)')
|
|
1097
|
+
.option('--json', 'saída em JSON estruturado')
|
|
1098
|
+
.action(async (opts) => {
|
|
1099
|
+
const { runDbList } = await import('./commands/db.js');
|
|
1100
|
+
await runDbList({
|
|
1101
|
+
productId: opts.productId,
|
|
1102
|
+
engine: opts.engine,
|
|
1103
|
+
status: opts.status,
|
|
1104
|
+
json: !!opts.json,
|
|
1105
|
+
});
|
|
1106
|
+
});
|
|
1107
|
+
// ── neetru db status <dbId> ───────────────────────────────────────────
|
|
1108
|
+
dbCmd
|
|
1109
|
+
.command('status <dbId>')
|
|
1110
|
+
.description('Detalhar banco + status de provisionamento/saúde')
|
|
1111
|
+
.option('--json', 'saída em JSON estruturado')
|
|
1112
|
+
.action(async (dbId, opts) => {
|
|
1113
|
+
const { runDbStatus } = await import('./commands/db.js');
|
|
1114
|
+
await runDbStatus(dbId, { json: !!opts.json });
|
|
1115
|
+
});
|
|
1116
|
+
// ── neetru db init ────────────────────────────────────────────────────
|
|
1117
|
+
// D-3: opções legadas --out e --force removidas. db init faz UMA coisa.
|
|
1118
|
+
// D-4: --env aceita dev-local (canônico) ou dev (alias explícito com aviso).
|
|
978
1119
|
dbCmd
|
|
979
1120
|
.command('init')
|
|
980
|
-
.description('
|
|
981
|
-
.option('--
|
|
982
|
-
.option('--
|
|
1121
|
+
.description('Registrar banco no Core + gravar .neetru/db.json + scaffoldar db/schema.ts')
|
|
1122
|
+
.option('--name <name>', 'nome do banco (interativo se ausente)')
|
|
1123
|
+
.option('--engine <engine>', 'engine: cloud-sql-postgres | vm-postgres-single | firestore-instance | …')
|
|
1124
|
+
.option('--env <env>', 'ambiente: dev-local (padrão) | staging | production')
|
|
1125
|
+
.option('--product-id <id>', 'override do productId (default: slug do neetru.config.json)')
|
|
1126
|
+
.option('-y, --yes', 'modo não-interativo (usa defaults)')
|
|
983
1127
|
.action(async (opts) => {
|
|
984
1128
|
const { runDbInit } = await import('./commands/db.js');
|
|
985
|
-
await runDbInit({
|
|
1129
|
+
await runDbInit({
|
|
1130
|
+
name: opts.name,
|
|
1131
|
+
engine: opts.engine,
|
|
1132
|
+
env: opts.env,
|
|
1133
|
+
productId: opts.productId,
|
|
1134
|
+
yes: !!opts.yes,
|
|
1135
|
+
});
|
|
986
1136
|
});
|
|
1137
|
+
// ── neetru db apply ───────────────────────────────────────────────────
|
|
1138
|
+
// D-4: --env usa dev-local como default canônico.
|
|
987
1139
|
dbCmd
|
|
988
|
-
.command('
|
|
989
|
-
.description('
|
|
990
|
-
.option('--
|
|
991
|
-
.
|
|
992
|
-
|
|
993
|
-
|
|
1140
|
+
.command('apply')
|
|
1141
|
+
.description('Executar pipeline de migração + enviar ao Core (POST /api/cli/v1/db/migrations/push)')
|
|
1142
|
+
.option('--db <name>', 'banco alvo (interativo se mais de um registrado)')
|
|
1143
|
+
.option('--env <env>', 'ambiente alvo: dev-local (padrão) | staging | production')
|
|
1144
|
+
.option('--schema <path>', 'caminho do schema (default: db/schema.ts)')
|
|
1145
|
+
.option('--dry-run', 'calcula o diff mas NÃO envia ao Core')
|
|
1146
|
+
.option('-y, --yes', 'pula a confirmação interativa')
|
|
1147
|
+
.action(async (opts) => {
|
|
1148
|
+
const { runDbApply } = await import('./commands/db.js');
|
|
1149
|
+
await runDbApply({
|
|
1150
|
+
dbName: opts.db,
|
|
1151
|
+
env: opts.env,
|
|
1152
|
+
schemaPath: opts.schema,
|
|
1153
|
+
dryRun: !!opts.dryRun,
|
|
1154
|
+
yes: !!opts.yes,
|
|
1155
|
+
});
|
|
994
1156
|
});
|
|
1157
|
+
// ── neetru db migrations ──────────────────────────────────────────────
|
|
1158
|
+
const dbMigrationsCmd = dbCmd
|
|
1159
|
+
.command('migrations')
|
|
1160
|
+
.description('Operar migrações de banco');
|
|
1161
|
+
dbMigrationsCmd
|
|
1162
|
+
.command('list')
|
|
1163
|
+
.description('Listar migrações registradas (GET /api/cli/v1/db/migrations)')
|
|
1164
|
+
.option('--db <dbId>', 'filtrar por ID do banco')
|
|
1165
|
+
.option('--json', 'saída em JSON estruturado')
|
|
1166
|
+
.action(async (opts) => {
|
|
1167
|
+
const { runDbMigrationsList } = await import('./commands/db.js');
|
|
1168
|
+
await runDbMigrationsList({ dbId: opts.db, json: !!opts.json });
|
|
1169
|
+
});
|
|
1170
|
+
dbMigrationsCmd
|
|
1171
|
+
.command('confirm <migrationId>')
|
|
1172
|
+
.description('Confirmar migração destrutiva (POST /api/cli/v1/db/migrations/[id]/confirm — exige MFA)')
|
|
1173
|
+
.requiredOption('--mfa <token>', 'código TOTP step-up MFA')
|
|
1174
|
+
.option('--json', 'saída em JSON')
|
|
1175
|
+
.action(async (migrationId, opts) => {
|
|
1176
|
+
const { runDbMigrationsConfirm } = await import('./commands/db.js');
|
|
1177
|
+
await runDbMigrationsConfirm(migrationId, { mfa: opts.mfa, json: !!opts.json });
|
|
1178
|
+
});
|
|
1179
|
+
// D-3: neetru db migrate removido (legado Sprint 10 cortado).
|
|
1180
|
+
// ── neetru db backups <dbId> ──────────────────────────────────────────
|
|
1181
|
+
dbCmd
|
|
1182
|
+
.command('backups <dbId>')
|
|
1183
|
+
.description('Listar backups de um banco (GET /api/cli/v1/db/[id]/backups)')
|
|
1184
|
+
.option('--json', 'saída em JSON estruturado')
|
|
1185
|
+
.action(async (dbId, opts) => {
|
|
1186
|
+
const { runDbBackups } = await import('./commands/db.js');
|
|
1187
|
+
await runDbBackups(dbId, { json: !!opts.json });
|
|
1188
|
+
});
|
|
1189
|
+
// ── neetru db restore <dbId> ──────────────────────────────────────────
|
|
995
1190
|
dbCmd
|
|
996
|
-
.command('
|
|
997
|
-
.description('
|
|
998
|
-
.
|
|
1191
|
+
.command('restore <dbId>')
|
|
1192
|
+
.description('Restaurar banco a partir de backup (POST /api/cli/v1/db/[id]/restore — exige MFA)')
|
|
1193
|
+
.requiredOption('--mfa <token>', 'código TOTP step-up MFA (obrigatório — operação destrutiva)')
|
|
1194
|
+
.option('--json', 'saída em JSON')
|
|
1195
|
+
.action(async (dbId, opts) => {
|
|
1196
|
+
const { runDbRestore } = await import('./commands/db.js');
|
|
1197
|
+
await runDbRestore(dbId, { mfa: opts.mfa, json: !!opts.json });
|
|
1198
|
+
});
|
|
1199
|
+
// ── neetru db hosts ───────────────────────────────────────────────────
|
|
1200
|
+
// Alias: também acessível via `neetru db-hosts` (top-level).
|
|
1201
|
+
dbCmd
|
|
1202
|
+
.command('hosts')
|
|
1203
|
+
.description('Listar VM hosts de banco e densidade (GET /api/cli/v1/servers?capacity=true&db=true)')
|
|
1204
|
+
.option('--json', 'saída em JSON estruturado')
|
|
1205
|
+
.action(async (opts) => {
|
|
1206
|
+
const { runDbHosts } = await import('./commands/db.js');
|
|
1207
|
+
await runDbHosts({ json: !!opts.json });
|
|
1208
|
+
});
|
|
1209
|
+
// D-3: neetru db seed removido (legado Sprint 10 cortado).
|
|
1210
|
+
// ── neetru db-hosts (top-level alias de `neetru db hosts`) ───────────
|
|
1211
|
+
program
|
|
1212
|
+
.command('db-hosts')
|
|
1213
|
+
.description('Listar VM hosts de banco e densidade (alias de `neetru db hosts`)')
|
|
1214
|
+
.option('--json', 'saída em JSON estruturado')
|
|
999
1215
|
.action(async (opts) => {
|
|
1000
|
-
const {
|
|
1001
|
-
await
|
|
1216
|
+
const { runDbHosts } = await import('./commands/db.js');
|
|
1217
|
+
await runDbHosts({ json: !!opts.json });
|
|
1002
1218
|
});
|
|
1003
1219
|
// ── neetru fn ─────────────────────────────────────────────────────────
|
|
1004
1220
|
const fnCmd = program
|