@neetru/cli 2.29.0 → 2.32.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 +141 -0
- package/README.md +63 -17
- package/dist/cli-kit/choices.d.ts +33 -0
- package/dist/cli-kit/choices.js +32 -0
- package/dist/cli-kit/command-context.d.ts +98 -0
- package/dist/cli-kit/command-context.js +108 -0
- package/dist/cli-kit/errors.d.ts +79 -0
- package/dist/cli-kit/errors.js +94 -0
- package/dist/cli-kit/index.d.ts +8 -0
- package/dist/cli-kit/index.js +8 -0
- package/dist/cli-kit/suggest.d.ts +74 -0
- package/dist/cli-kit/suggest.js +207 -0
- package/dist/commands/admin/oidc-login.js +1 -1
- package/dist/commands/admin/sdk-credential.js +1 -1
- package/dist/commands/autocomplete.d.ts +1 -1
- package/dist/commands/autocomplete.js +1 -0
- package/dist/commands/bug.d.ts +59 -0
- package/dist/commands/bug.js +114 -2
- package/dist/commands/build.d.ts +24 -1
- package/dist/commands/build.js +195 -73
- package/dist/commands/chat.d.ts +94 -1
- package/dist/commands/chat.js +258 -26
- package/dist/commands/customers.js +1 -1
- package/dist/commands/db-move.js +3 -3
- package/dist/commands/db.js +17 -24
- package/dist/commands/deploy.d.ts +136 -2
- package/dist/commands/deploy.js +547 -69
- package/dist/commands/deployments.js +11 -6
- package/dist/commands/dev-context.js +15 -5
- package/dist/commands/dev-up.d.ts +7 -5
- package/dist/commands/dev-up.js +24 -23
- package/dist/commands/docs-produto.d.ts +90 -0
- package/dist/commands/docs-produto.js +384 -0
- package/dist/commands/doctor.js +36 -1
- package/dist/commands/domains.js +85 -4
- package/dist/commands/env.d.ts +9 -3
- package/dist/commands/env.js +23 -3
- package/dist/commands/infra-read.js +2 -2
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +14 -1
- package/dist/commands/login.js +35 -8
- package/dist/commands/logs.js +12 -4
- package/dist/commands/mobile.js +33 -9
- package/dist/commands/new.d.ts +31 -1
- package/dist/commands/new.js +94 -4
- package/dist/commands/open.js +16 -6
- package/dist/commands/ops.js +1 -1
- package/dist/commands/products-db.d.ts +1 -0
- package/dist/commands/products-db.js +41 -8
- package/dist/commands/products.d.ts +17 -3
- package/dist/commands/products.js +84 -16
- package/dist/commands/promote.js +30 -5
- package/dist/commands/secrets.d.ts +91 -0
- package/dist/commands/secrets.js +471 -0
- package/dist/commands/servers.js +6 -4
- package/dist/commands/status.js +2 -2
- package/dist/commands/support.js +5 -3
- package/dist/commands/tenants.js +28 -16
- package/dist/commands/upgrade.d.ts +9 -0
- package/dist/commands/upgrade.js +50 -1
- package/dist/commands/vm-memory.js +1 -0
- package/dist/commands/webhooks.d.ts +2 -0
- package/dist/commands/webhooks.js +9 -3
- package/dist/commands/workspaces.js +42 -11
- package/dist/index.js +142 -20
- package/dist/lib/api-client.d.ts +22 -1
- package/dist/lib/api-client.js +79 -8
- package/dist/lib/api-error.d.ts +14 -0
- package/dist/lib/api-error.js +107 -46
- package/dist/lib/build-targets.d.ts +127 -0
- package/dist/lib/build-targets.js +348 -0
- package/dist/lib/cli-error.d.ts +13 -0
- package/dist/lib/cli-error.js +24 -0
- package/dist/lib/cli-write.d.ts +43 -9
- package/dist/lib/cli-write.js +154 -45
- package/dist/lib/compose-generator.d.ts +13 -9
- package/dist/lib/compose-generator.js +28 -60
- package/dist/lib/config-schema.d.ts +36 -2
- package/dist/lib/config-schema.js +11 -0
- package/dist/lib/db-local/db-json.d.ts +1 -1
- package/dist/lib/db-local/db-json.js +13 -5
- package/dist/lib/db-local/env.d.ts +15 -3
- package/dist/lib/db-local/env.js +37 -10
- package/dist/lib/db-pipeline/build-deps.d.ts +5 -1
- package/dist/lib/db-pipeline/build-deps.js +23 -3
- package/dist/lib/db-pipeline/types.d.ts +6 -2
- package/dist/lib/db-pipeline/types.js +0 -18
- package/dist/lib/deploy-target-contract.d.ts +152 -0
- package/dist/lib/deploy-target-contract.js +411 -0
- package/dist/lib/env-file-do-build.d.ts +19 -0
- package/dist/lib/env-file-do-build.js +44 -0
- package/dist/lib/envs.d.ts +108 -0
- package/dist/lib/envs.js +127 -0
- package/dist/lib/fs-seguro.d.ts +63 -0
- package/dist/lib/fs-seguro.js +108 -0
- package/dist/lib/mobile-local/mobile-json.js +10 -4
- package/dist/lib/pickers.d.ts +44 -7
- package/dist/lib/pickers.js +60 -4
- package/dist/lib/product-docs/check.d.ts +62 -0
- package/dist/lib/product-docs/check.js +489 -0
- package/dist/lib/product-docs/config.d.ts +66 -0
- package/dist/lib/product-docs/config.js +234 -0
- package/dist/lib/product-docs/dates.d.ts +17 -0
- package/dist/lib/product-docs/dates.js +41 -0
- package/dist/lib/product-docs/frontmatter.d.ts +43 -0
- package/dist/lib/product-docs/frontmatter.js +302 -0
- package/dist/lib/product-docs/git.d.ts +16 -0
- package/dist/lib/product-docs/git.js +92 -0
- package/dist/lib/product-docs/markdown.d.ts +27 -0
- package/dist/lib/product-docs/markdown.js +98 -0
- package/dist/lib/product-docs/ops.d.ts +133 -0
- package/dist/lib/product-docs/ops.js +975 -0
- package/dist/lib/product-docs/structure.d.ts +61 -0
- package/dist/lib/product-docs/structure.js +239 -0
- package/dist/lib/product-docs/sync.d.ts +107 -0
- package/dist/lib/product-docs/sync.js +322 -0
- package/dist/lib/product-docs/taxonomy.d.ts +46 -0
- package/dist/lib/product-docs/taxonomy.js +163 -0
- package/dist/lib/product-docs/templates.d.ts +53 -0
- package/dist/lib/product-docs/templates.js +245 -0
- package/dist/lib/public-secret-scan.d.ts +117 -0
- package/dist/lib/public-secret-scan.js +771 -0
- package/dist/lib/render.d.ts +16 -0
- package/dist/lib/render.js +34 -4
- package/dist/lib/segredo-produto.d.ts +124 -0
- package/dist/lib/segredo-produto.js +336 -0
- package/dist/lib/texto-utf8.d.ts +96 -0
- package/dist/lib/texto-utf8.js +196 -0
- package/package.json +2 -1
- package/dist/cli-kit/format.js.map +0 -1
- package/dist/cli-kit/glyphs.js.map +0 -1
- package/dist/cli-kit/index.js.map +0 -1
- package/dist/cli-kit/palette.js.map +0 -1
- package/dist/commands/add.js.map +0 -1
- package/dist/commands/admin/iam-check.js.map +0 -1
- package/dist/commands/admin/oidc-login.js.map +0 -1
- package/dist/commands/admin/sdk-credential.js.map +0 -1
- package/dist/commands/agent-release.js.map +0 -1
- package/dist/commands/agent-write.js.map +0 -1
- package/dist/commands/ai-models.js.map +0 -1
- package/dist/commands/ai.js.map +0 -1
- package/dist/commands/api-catalog.js.map +0 -1
- package/dist/commands/archive.js.map +0 -1
- package/dist/commands/artifact-registry.js.map +0 -1
- package/dist/commands/audit.js.map +0 -1
- package/dist/commands/auth.js.map +0 -1
- package/dist/commands/autocomplete.js.map +0 -1
- package/dist/commands/billing.js.map +0 -1
- package/dist/commands/bootstrap.js.map +0 -1
- package/dist/commands/bug.js.map +0 -1
- package/dist/commands/build.js.map +0 -1
- package/dist/commands/chat-menu.js.map +0 -1
- package/dist/commands/chat.js.map +0 -1
- package/dist/commands/cloud-run.js.map +0 -1
- package/dist/commands/code.js.map +0 -1
- package/dist/commands/config.js.map +0 -1
- package/dist/commands/customers.js.map +0 -1
- package/dist/commands/db-move.js.map +0 -1
- package/dist/commands/db.js.map +0 -1
- package/dist/commands/deploy.js.map +0 -1
- package/dist/commands/deployments.js.map +0 -1
- package/dist/commands/dev-context.js.map +0 -1
- package/dist/commands/dev-up.js.map +0 -1
- package/dist/commands/dev.js.map +0 -1
- package/dist/commands/docs.js.map +0 -1
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/domains.js.map +0 -1
- package/dist/commands/dr.js.map +0 -1
- package/dist/commands/env.js.map +0 -1
- package/dist/commands/hosting-write.js.map +0 -1
- package/dist/commands/infra-read.js.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/login.js.map +0 -1
- package/dist/commands/logout.js.map +0 -1
- package/dist/commands/logs.js.map +0 -1
- package/dist/commands/mobile.js.map +0 -1
- package/dist/commands/mocks.js.map +0 -1
- package/dist/commands/new.js.map +0 -1
- package/dist/commands/open.js.map +0 -1
- package/dist/commands/ops.js.map +0 -1
- package/dist/commands/products-db.js.map +0 -1
- package/dist/commands/products.js.map +0 -1
- package/dist/commands/promote.js.map +0 -1
- package/dist/commands/publish.js.map +0 -1
- package/dist/commands/schema.js.map +0 -1
- package/dist/commands/servers.js.map +0 -1
- package/dist/commands/smoke.js.map +0 -1
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/support.js.map +0 -1
- package/dist/commands/surface-status.js.map +0 -1
- package/dist/commands/tenants.js.map +0 -1
- package/dist/commands/ui.js.map +0 -1
- package/dist/commands/upgrade.js.map +0 -1
- package/dist/commands/validate.js.map +0 -1
- package/dist/commands/vm-memory.js.map +0 -1
- package/dist/commands/vm.js.map +0 -1
- package/dist/commands/webhooks.js.map +0 -1
- package/dist/commands/whoami.js.map +0 -1
- package/dist/commands/workspaces.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/agent-artifact-url.js.map +0 -1
- package/dist/lib/agent-commands.js.map +0 -1
- package/dist/lib/ai/auth-discovery.js.map +0 -1
- package/dist/lib/ai/context.js.map +0 -1
- package/dist/lib/ai/orchestrator.js.map +0 -1
- package/dist/lib/api-client.js.map +0 -1
- package/dist/lib/api-error.js.map +0 -1
- package/dist/lib/auth.js.map +0 -1
- package/dist/lib/cli-read.js.map +0 -1
- package/dist/lib/cli-write.js.map +0 -1
- package/dist/lib/code-agent-budget.js.map +0 -1
- package/dist/lib/code-agent-files.js.map +0 -1
- package/dist/lib/code-agent-gateway.js.map +0 -1
- package/dist/lib/code-agent-git-tools.js.map +0 -1
- package/dist/lib/code-agent-protocol.js.map +0 -1
- package/dist/lib/code-agent-session.js.map +0 -1
- package/dist/lib/code-agent-settings.js.map +0 -1
- package/dist/lib/code-agent-skills.js.map +0 -1
- package/dist/lib/code-agent-subagents.js.map +0 -1
- package/dist/lib/code-agent-tools.js.map +0 -1
- package/dist/lib/code-agent-tui.js.map +0 -1
- package/dist/lib/code-agent-types.js.map +0 -1
- package/dist/lib/code-agent-ui.js.map +0 -1
- package/dist/lib/code-agent-web-tools.js.map +0 -1
- package/dist/lib/code-agent-write-tools.js.map +0 -1
- package/dist/lib/compose-generator.js.map +0 -1
- package/dist/lib/config-schema.js.map +0 -1
- package/dist/lib/config.js.map +0 -1
- package/dist/lib/db-local/db-json.js.map +0 -1
- package/dist/lib/db-local/env.js.map +0 -1
- package/dist/lib/db-local/fingerprint.js.map +0 -1
- package/dist/lib/db-local/index.js.map +0 -1
- package/dist/lib/db-pipeline/build-deps.js.map +0 -1
- package/dist/lib/db-pipeline/errors.js.map +0 -1
- package/dist/lib/db-pipeline/index.js.map +0 -1
- package/dist/lib/db-pipeline/pipeline.js.map +0 -1
- package/dist/lib/db-pipeline/rehearse.js.map +0 -1
- package/dist/lib/db-pipeline/types.js.map +0 -1
- package/dist/lib/dev-local-context.js.map +0 -1
- package/dist/lib/iam-preflight.js.map +0 -1
- package/dist/lib/mobile-local/index.js.map +0 -1
- package/dist/lib/mobile-local/mobile-json.js.map +0 -1
- package/dist/lib/pickers.js.map +0 -1
- package/dist/lib/product-config.js.map +0 -1
- package/dist/lib/render.js.map +0 -1
- package/dist/lib/schema-cache.js.map +0 -1
- package/dist/lib/sse.js.map +0 -1
- package/dist/lib/telemetry.js.map +0 -1
- package/dist/lib/token-resolver.js.map +0 -1
- package/dist/lib/url-allowlist.js.map +0 -1
- package/dist/lib/version-check.js.map +0 -1
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/logo.js.map +0 -1
- package/dist/utils/safe-exit.js.map +0 -1
- package/dist/utils/spinner-registry.js.map +0 -1
- package/dist/version.js.map +0 -1
- package/templates/dev/Dockerfile.agent +0 -39
- package/templates/dev/agent-entrypoint.sh +0 -41
- package/templates/dev/docker-compose.dev.yml +0 -63
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Saída do processo a partir de um `NeetruCliError` (bug_89d2497e, etapa 3).
|
|
3
|
+
*
|
|
4
|
+
* O cli-kit monta o erro (puro); aqui ele é impresso — JSON no stdout em
|
|
5
|
+
* `--json`, texto humano no stderr fora dele — e o processo sai com o código
|
|
6
|
+
* de saída DO ERRO. Ponto único: `handleApiError`, `resolveStepUp`, a validação
|
|
7
|
+
* de `--env` e o trap global de `index.ts` passam por aqui.
|
|
8
|
+
*/
|
|
9
|
+
import { NeetruCliError } from '../cli-kit/errors.js';
|
|
10
|
+
/** Imprime o erro e devolve o código de saída — sem encerrar. */
|
|
11
|
+
export declare function emitCliError(error: NeetruCliError, json?: boolean): number;
|
|
12
|
+
/** Imprime o erro e encerra com o código de saída dele. Nunca retorna. */
|
|
13
|
+
export declare function exitWithCliError(error: NeetruCliError, json?: boolean): never;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Saída do processo a partir de um `NeetruCliError` (bug_89d2497e, etapa 3).
|
|
3
|
+
*
|
|
4
|
+
* O cli-kit monta o erro (puro); aqui ele é impresso — JSON no stdout em
|
|
5
|
+
* `--json`, texto humano no stderr fora dele — e o processo sai com o código
|
|
6
|
+
* de saída DO ERRO. Ponto único: `handleApiError`, `resolveStepUp`, a validação
|
|
7
|
+
* de `--env` e o trap global de `index.ts` passam por aqui.
|
|
8
|
+
*/
|
|
9
|
+
import { renderCliError } from '../cli-kit/errors.js';
|
|
10
|
+
import { log } from '../utils/logger.js';
|
|
11
|
+
import { safeExit } from '../utils/safe-exit.js';
|
|
12
|
+
/** Imprime o erro e devolve o código de saída — sem encerrar. */
|
|
13
|
+
export function emitCliError(error, json) {
|
|
14
|
+
if (json)
|
|
15
|
+
console.log(JSON.stringify(error.toJSON()));
|
|
16
|
+
else
|
|
17
|
+
log.error(renderCliError(error));
|
|
18
|
+
return error.exit;
|
|
19
|
+
}
|
|
20
|
+
/** Imprime o erro e encerra com o código de saída dele. Nunca retorna. */
|
|
21
|
+
export function exitWithCliError(error, json) {
|
|
22
|
+
return safeExit(emitCliError(error, json));
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=cli-error.js.map
|
package/dist/lib/cli-write.d.ts
CHANGED
|
@@ -18,6 +18,27 @@ export declare function saveMfaSession(mfaSessionToken: string, expiresAt: strin
|
|
|
18
18
|
* apagado junto com o Bearer token.
|
|
19
19
|
*/
|
|
20
20
|
export declare function clearMfaSession(): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* uid dono de um token de sessão MFA. O Core emite
|
|
23
|
+
* `<uid_base64url>.<issuedAt_hex>.<hmac_sha256_hex>` (`createCliMfaSessionToken`
|
|
24
|
+
* em `src/lib/auth-mfa-session.ts`): o uid é a parte ASSINADA, não segredo — o
|
|
25
|
+
* servidor só aceita a sessão se ele bater com o uid do Bearer. `null` se o
|
|
26
|
+
* formato não for reconhecido.
|
|
27
|
+
*/
|
|
28
|
+
export declare function mfaSessionOwnerUid(token: string): string | null;
|
|
29
|
+
/**
|
|
30
|
+
* Descarta a sessão MFA salva quando ela não é do `uid` que acabou de logar.
|
|
31
|
+
*
|
|
32
|
+
* A8 (2026-10-13): `neetru login` com outra conta trocava o Bearer mas deixava
|
|
33
|
+
* o `mfa-session.json` da conta anterior. O Core recusa sessão de outro uid,
|
|
34
|
+
* então TODO comando destrutivo tomava 401 `mfa_required` por até 1h (e, antes
|
|
35
|
+
* do conserto da precedência em `resolveStepUp`, nem `--mfa-token` salvava).
|
|
36
|
+
* Sessão de dono desconhecido (arquivo corrompido, formato não reconhecido)
|
|
37
|
+
* também sai — o servidor recusaria do mesmo jeito. Sessão do MESMO uid fica
|
|
38
|
+
* (re-login na mesma conta não deve exigir TOTP de novo). Retorna `true` se
|
|
39
|
+
* apagou.
|
|
40
|
+
*/
|
|
41
|
+
export declare function discardMfaSessionOfOtherUid(uid: string): Promise<boolean>;
|
|
21
42
|
export interface ConfirmOptions {
|
|
22
43
|
/** `--yes` / `--force` — pula a confirmação (modo script/CI). */
|
|
23
44
|
yes?: boolean;
|
|
@@ -25,6 +46,17 @@ export interface ConfirmOptions {
|
|
|
25
46
|
/** Saída em JSON — não imprime prompt humano. */
|
|
26
47
|
json?: boolean;
|
|
27
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* O que dizer quando a confirmação não pode ser perguntada (P105 /
|
|
51
|
+
* bug_89d2497e). Cita só as flags de confirmação que o comando EM EXECUÇÃO
|
|
52
|
+
* declara: o texto fixo "use --yes (ou --force)" chegava a 8 comandos que
|
|
53
|
+
* declaram `--yes` mas não `--force` (medido na árvore do Commander em
|
|
54
|
+
* 2026-10-18: `servers pgbouncer sync-userlist`, `products memory set`,
|
|
55
|
+
* `vm memory set`, `db move start|abort|decommission`, `promote execute`,
|
|
56
|
+
* `mobile revoke`) — quem seguisse com `--force` tomava "unknown option".
|
|
57
|
+
* Sem nenhuma das duas (ou fora do Commander, como no menu), não cita flag.
|
|
58
|
+
*/
|
|
59
|
+
export declare function confirmationAdvice(modo: 'json' | 'nao-interativo'): string;
|
|
28
60
|
/**
|
|
29
61
|
* Gate de confirmação pra operações DESTRUTIVAS (suspend, deactivate, delete,
|
|
30
62
|
* rollback, archive, yank). Se `--yes`/`--force` foi passado, retorna sem
|
|
@@ -58,19 +90,21 @@ export interface StepUpOptions extends ConfirmOptions {
|
|
|
58
90
|
}
|
|
59
91
|
/**
|
|
60
92
|
* Resolve o que uma operação destrutiva TOP-TIER precisa mandar pro servidor:
|
|
61
|
-
* - `headers`: `X-Neetru-MFA-
|
|
62
|
-
* (
|
|
93
|
+
* - `headers`: `X-Neetru-MFA-Token` (TOTP fresco) OU `X-Neetru-MFA-Session`
|
|
94
|
+
* (sessão de 1h) e/ou `X-Neetru-Dry-Run`.
|
|
63
95
|
*
|
|
64
96
|
* Ordem de preferência:
|
|
65
97
|
* 1. dry-run: sem MFA, só `X-Neetru-Dry-Run: true`.
|
|
66
|
-
* 2.
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* 3.
|
|
70
|
-
*
|
|
71
|
-
*
|
|
98
|
+
* 2. `--mfa-token` explícito: manda `X-Neetru-MFA-Token` — e também a sessão
|
|
99
|
+
* salva, se houver (o Core tenta a sessão antes e não gasta o TOTP à toa).
|
|
100
|
+
* O código NUNCA é descartado em favor da sessão (A8).
|
|
101
|
+
* 3. Sessão de 1h salva localmente: usa `X-Neetru-MFA-Session` sem pedir
|
|
102
|
+
* TOTP. Silencioso — o operador não precisa saber que a sessão está ativa.
|
|
103
|
+
* 4. Prompt interativo do TOTP. Em `--json`/não-interativo sem código nem
|
|
104
|
+
* sessão, encerra com instrução clara — o servidor recusaria de qualquer
|
|
105
|
+
* forma (fail-closed).
|
|
72
106
|
*
|
|
73
|
-
* feature mfa-session (2026-06-12): o item
|
|
107
|
+
* feature mfa-session (2026-06-12): o item 3 elimina o re-prompt TOTP a cada
|
|
74
108
|
* comando destrutivo quando o operador já rodou `neetru auth mfa-session`.
|
|
75
109
|
*/
|
|
76
110
|
export declare function resolveStepUp(opts: StepUpOptions): Promise<{
|
package/dist/lib/cli-write.js
CHANGED
|
@@ -20,6 +20,9 @@ import { requireToken, handleApiError } from './cli-read.js';
|
|
|
20
20
|
import { CliApiError } from './api-client.js';
|
|
21
21
|
import { log } from '../utils/logger.js';
|
|
22
22
|
import { safeExit } from '../utils/safe-exit.js';
|
|
23
|
+
import { EXIT_CODES, NeetruCliError } from '../cli-kit/errors.js';
|
|
24
|
+
import { adviseCommand, adviseFlag, declaredFlags } from '../cli-kit/command-context.js';
|
|
25
|
+
import { exitWithCliError } from './cli-error.js';
|
|
23
26
|
export { requireToken, handleApiError };
|
|
24
27
|
function getMfaSessionFilePath() {
|
|
25
28
|
return join(homedir(), '.config', 'neetru-cli', 'mfa-session.json');
|
|
@@ -89,6 +92,55 @@ export async function clearMfaSession() {
|
|
|
89
92
|
// Ignora — arquivo já inexistente ou sem permissão.
|
|
90
93
|
}
|
|
91
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* uid dono de um token de sessão MFA. O Core emite
|
|
97
|
+
* `<uid_base64url>.<issuedAt_hex>.<hmac_sha256_hex>` (`createCliMfaSessionToken`
|
|
98
|
+
* em `src/lib/auth-mfa-session.ts`): o uid é a parte ASSINADA, não segredo — o
|
|
99
|
+
* servidor só aceita a sessão se ele bater com o uid do Bearer. `null` se o
|
|
100
|
+
* formato não for reconhecido.
|
|
101
|
+
*/
|
|
102
|
+
export function mfaSessionOwnerUid(token) {
|
|
103
|
+
const parts = token.split('.');
|
|
104
|
+
if (parts.length !== 3 || !parts[0])
|
|
105
|
+
return null;
|
|
106
|
+
try {
|
|
107
|
+
const uid = Buffer.from(parts[0], 'base64url').toString('utf8');
|
|
108
|
+
return /^[\x21-\x7e]+$/.test(uid) ? uid : null;
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Descarta a sessão MFA salva quando ela não é do `uid` que acabou de logar.
|
|
116
|
+
*
|
|
117
|
+
* A8 (2026-10-13): `neetru login` com outra conta trocava o Bearer mas deixava
|
|
118
|
+
* o `mfa-session.json` da conta anterior. O Core recusa sessão de outro uid,
|
|
119
|
+
* então TODO comando destrutivo tomava 401 `mfa_required` por até 1h (e, antes
|
|
120
|
+
* do conserto da precedência em `resolveStepUp`, nem `--mfa-token` salvava).
|
|
121
|
+
* Sessão de dono desconhecido (arquivo corrompido, formato não reconhecido)
|
|
122
|
+
* também sai — o servidor recusaria do mesmo jeito. Sessão do MESMO uid fica
|
|
123
|
+
* (re-login na mesma conta não deve exigir TOTP de novo). Retorna `true` se
|
|
124
|
+
* apagou.
|
|
125
|
+
*/
|
|
126
|
+
export async function discardMfaSessionOfOtherUid(uid) {
|
|
127
|
+
const path = getMfaSessionFilePath();
|
|
128
|
+
if (!existsSync(path))
|
|
129
|
+
return false;
|
|
130
|
+
let owner = null;
|
|
131
|
+
try {
|
|
132
|
+
const data = JSON.parse(readFileSync(path, 'utf8'));
|
|
133
|
+
if (typeof data.mfaSessionToken === 'string')
|
|
134
|
+
owner = mfaSessionOwnerUid(data.mfaSessionToken);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// corrompido → dono desconhecido → descarta
|
|
138
|
+
}
|
|
139
|
+
if (owner !== null && owner === uid)
|
|
140
|
+
return false;
|
|
141
|
+
await clearMfaSession();
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
92
144
|
/**
|
|
93
145
|
* Pede uma confirmação interativa `y/N` no terminal. Resolve `true` se o
|
|
94
146
|
* operador digitou `y`/`yes` (case-insensitive); `false` caso contrário.
|
|
@@ -108,6 +160,31 @@ function promptYesNo(question) {
|
|
|
108
160
|
});
|
|
109
161
|
});
|
|
110
162
|
}
|
|
163
|
+
/** As flags que pulam a confirmação, na ordem em que o conselho as cita. */
|
|
164
|
+
const FLAGS_DE_CONFIRMACAO = ['--yes', '--force'];
|
|
165
|
+
/**
|
|
166
|
+
* O que dizer quando a confirmação não pode ser perguntada (P105 /
|
|
167
|
+
* bug_89d2497e). Cita só as flags de confirmação que o comando EM EXECUÇÃO
|
|
168
|
+
* declara: o texto fixo "use --yes (ou --force)" chegava a 8 comandos que
|
|
169
|
+
* declaram `--yes` mas não `--force` (medido na árvore do Commander em
|
|
170
|
+
* 2026-10-18: `servers pgbouncer sync-userlist`, `products memory set`,
|
|
171
|
+
* `vm memory set`, `db move start|abort|decommission`, `promote execute`,
|
|
172
|
+
* `mobile revoke`) — quem seguisse com `--force` tomava "unknown option".
|
|
173
|
+
* Sem nenhuma das duas (ou fora do Commander, como no menu), não cita flag.
|
|
174
|
+
*/
|
|
175
|
+
export function confirmationAdvice(modo) {
|
|
176
|
+
const flags = declaredFlags(FLAGS_DE_CONFIRMACAO);
|
|
177
|
+
if (modo === 'json') {
|
|
178
|
+
return flags.length > 0
|
|
179
|
+
? `Operação destrutiva em modo --json exige ${flags[0]}.`
|
|
180
|
+
: 'Operação destrutiva em modo --json exige confirmação, e este comando não tem como confirmar sem perguntar.';
|
|
181
|
+
}
|
|
182
|
+
if (flags.length === 0) {
|
|
183
|
+
return 'Terminal não-interativo: esta operação destrutiva só pode ser confirmada num terminal interativo.';
|
|
184
|
+
}
|
|
185
|
+
const lista = flags.length > 1 ? `${flags[0]} (ou ${flags[1]})` : flags[0];
|
|
186
|
+
return `Terminal não-interativo: use ${lista} para confirmar operações destrutivas.`;
|
|
187
|
+
}
|
|
111
188
|
/**
|
|
112
189
|
* Gate de confirmação pra operações DESTRUTIVAS (suspend, deactivate, delete,
|
|
113
190
|
* rollback, archive, yank). Se `--yes`/`--force` foi passado, retorna sem
|
|
@@ -129,7 +206,7 @@ export async function confirmDestructive(message, opts) {
|
|
|
129
206
|
console.log(JSON.stringify({
|
|
130
207
|
ok: false,
|
|
131
208
|
error: 'confirmation_required',
|
|
132
|
-
message: '
|
|
209
|
+
message: confirmationAdvice('json'),
|
|
133
210
|
}));
|
|
134
211
|
safeExit(1);
|
|
135
212
|
}
|
|
@@ -137,7 +214,7 @@ export async function confirmDestructive(message, opts) {
|
|
|
137
214
|
const confirmed = await promptYesNo('Confirmar?');
|
|
138
215
|
if (!confirmed) {
|
|
139
216
|
if (!process.stdin.isTTY) {
|
|
140
|
-
log.error('
|
|
217
|
+
log.error(confirmationAdvice('nao-interativo'));
|
|
141
218
|
}
|
|
142
219
|
else {
|
|
143
220
|
log.dim('Operação cancelada.');
|
|
@@ -157,21 +234,56 @@ function promptLine(question) {
|
|
|
157
234
|
});
|
|
158
235
|
});
|
|
159
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* O step-up que dá pra mandar SEM interação, na ordem de precedência:
|
|
239
|
+
* 1. `--mfa-token` explícito → `X-Neetru-MFA-Token`;
|
|
240
|
+
* 2. sessão de 1h salva (`~/.config/neetru-cli/mfa-session.json`) →
|
|
241
|
+
* `X-Neetru-MFA-Session` (salvo `skipSession`).
|
|
242
|
+
* `{}` se não houver nenhum dos dois (aí o caller prompta ou falha fechado).
|
|
243
|
+
*
|
|
244
|
+
* A8 (2026-10-13): o código explícito VENCE a sessão. Antes `resolveStepUp`
|
|
245
|
+
* olhava a sessão primeiro e devolvia só `X-Neetru-MFA-Session`, descartando o
|
|
246
|
+
* `--mfa-token` em silêncio — enquanto `withStepUpRetry` fazia o contrário.
|
|
247
|
+
* Depois de `neetru login` com outra conta (sessão do uid anterior no disco,
|
|
248
|
+
* que o Core recusa), ~40 comandos destrutivos davam 401 por até 1h MESMO com
|
|
249
|
+
* `--mfa-token`. Quem digita o código está pedindo que ele seja usado. As duas
|
|
250
|
+
* funções agora decidem por aqui — uma regra só.
|
|
251
|
+
*/
|
|
252
|
+
function nonInteractiveStepUp(opts) {
|
|
253
|
+
const code = (opts.mfaToken ?? '').trim();
|
|
254
|
+
const savedSession = opts.skipSession ? null : loadMfaSession();
|
|
255
|
+
// Código explícito + sessão salva: manda OS DOIS (revisão do #78). O Core
|
|
256
|
+
// (`requireCliStepUpMfa`) tenta a sessão primeiro e só usa o TOTP se ela não
|
|
257
|
+
// servir — e o TOTP é de USO ÚNICO (`mfa-lockout`). Mandar só o código gastava
|
|
258
|
+
// o código à toa quando a sessão era válida, e o 2º comando com o mesmo código
|
|
259
|
+
// (agente com o código ditado, script) falhava com mfa_invalid. Com os dois, a
|
|
260
|
+
// sessão de OUTRA conta (o caso do A8) cai e o código ainda salva o pedido.
|
|
261
|
+
if (code) {
|
|
262
|
+
return savedSession
|
|
263
|
+
? { 'X-Neetru-MFA-Token': code, 'X-Neetru-MFA-Session': savedSession }
|
|
264
|
+
: { 'X-Neetru-MFA-Token': code };
|
|
265
|
+
}
|
|
266
|
+
if (savedSession)
|
|
267
|
+
return { 'X-Neetru-MFA-Session': savedSession };
|
|
268
|
+
return {};
|
|
269
|
+
}
|
|
160
270
|
/**
|
|
161
271
|
* Resolve o que uma operação destrutiva TOP-TIER precisa mandar pro servidor:
|
|
162
|
-
* - `headers`: `X-Neetru-MFA-
|
|
163
|
-
* (
|
|
272
|
+
* - `headers`: `X-Neetru-MFA-Token` (TOTP fresco) OU `X-Neetru-MFA-Session`
|
|
273
|
+
* (sessão de 1h) e/ou `X-Neetru-Dry-Run`.
|
|
164
274
|
*
|
|
165
275
|
* Ordem de preferência:
|
|
166
276
|
* 1. dry-run: sem MFA, só `X-Neetru-Dry-Run: true`.
|
|
167
|
-
* 2.
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
* 3.
|
|
171
|
-
*
|
|
172
|
-
*
|
|
277
|
+
* 2. `--mfa-token` explícito: manda `X-Neetru-MFA-Token` — e também a sessão
|
|
278
|
+
* salva, se houver (o Core tenta a sessão antes e não gasta o TOTP à toa).
|
|
279
|
+
* O código NUNCA é descartado em favor da sessão (A8).
|
|
280
|
+
* 3. Sessão de 1h salva localmente: usa `X-Neetru-MFA-Session` sem pedir
|
|
281
|
+
* TOTP. Silencioso — o operador não precisa saber que a sessão está ativa.
|
|
282
|
+
* 4. Prompt interativo do TOTP. Em `--json`/não-interativo sem código nem
|
|
283
|
+
* sessão, encerra com instrução clara — o servidor recusaria de qualquer
|
|
284
|
+
* forma (fail-closed).
|
|
173
285
|
*
|
|
174
|
-
* feature mfa-session (2026-06-12): o item
|
|
286
|
+
* feature mfa-session (2026-06-12): o item 3 elimina o re-prompt TOTP a cada
|
|
175
287
|
* comando destrutivo quando o operador já rodou `neetru auth mfa-session`.
|
|
176
288
|
*/
|
|
177
289
|
export async function resolveStepUp(opts) {
|
|
@@ -180,34 +292,35 @@ export async function resolveStepUp(opts) {
|
|
|
180
292
|
headers['X-Neetru-Dry-Run'] = 'true';
|
|
181
293
|
return { headers };
|
|
182
294
|
}
|
|
183
|
-
// ──
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
//
|
|
191
|
-
|
|
192
|
-
if (!
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
//
|
|
196
|
-
//
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
209
|
-
|
|
295
|
+
// ── Prioridades 2 e 3: código explícito, depois sessão de 1h ────────────
|
|
296
|
+
const ready = nonInteractiveStepUp(opts);
|
|
297
|
+
if (Object.keys(ready).length > 0)
|
|
298
|
+
return { headers: ready };
|
|
299
|
+
// ── Prioridade 4: prompt do TOTP ─────────────────────────────────────────
|
|
300
|
+
// bug auditoria 2026-06-30: em --json o prompt interativo de TOTP NÃO pode
|
|
301
|
+
// rodar NEM com TTY — ele escreveria a pergunta no stdout (corrompe o JSON)
|
|
302
|
+
// e penduraria um consumidor programático. Fail-CLOSED em --json OU sem TTY;
|
|
303
|
+
// só promptar em terminal interativo humano (não-json + TTY).
|
|
304
|
+
if (opts.json || opts.nonInteractive || !process.stdin.isTTY) {
|
|
305
|
+
// bug_89d2497e: o conselho só cita `--mfa-token` se o comando em execução
|
|
306
|
+
// declara a flag (mesmo defeito do bug_757b9746, do lado do step-up). O
|
|
307
|
+
// código de saída segue 1 e o JSON segue `{ ok, error:'mfa_required', message }`.
|
|
308
|
+
// P105: o comando alternativo (`neetru auth mfa-session`) também só é
|
|
309
|
+
// citado se existe na árvore do Commander.
|
|
310
|
+
const sessao = (withCommand, withoutCommand) => adviseCommand({ command: 'auth mfa-session', withCommand, withoutCommand });
|
|
311
|
+
const msg = adviseFlag({
|
|
312
|
+
flag: '--mfa-token',
|
|
313
|
+
withFlag: sessao('Operação destrutiva top-tier exige step-up MFA: passe --mfa-token <código TOTP> ' +
|
|
314
|
+
'(modo --json/não-interativo) ou rode `neetru auth mfa-session` para obter uma sessão de 1h.', 'Operação destrutiva top-tier exige step-up MFA: passe --mfa-token <código TOTP> ' +
|
|
315
|
+
'(modo --json/não-interativo).'),
|
|
316
|
+
withoutFlag: sessao('Operação destrutiva top-tier exige step-up MFA: rode `neetru auth mfa-session` ' +
|
|
317
|
+
'para obter uma sessão de 1h e repita o comando.', 'Operação destrutiva top-tier exige step-up MFA, e esta CLI não tem, neste comando, ' +
|
|
318
|
+
'como enviá-lo em modo --json/não-interativo.'),
|
|
319
|
+
});
|
|
320
|
+
exitWithCliError(new NeetruCliError(msg, { code: 'mfa_required', exit: EXIT_CODES.client }), opts.json);
|
|
321
|
+
return { headers }; // safeExit não retorna em prod; satisfaz o tipo + testes
|
|
210
322
|
}
|
|
323
|
+
const code = await promptLine('Código MFA (TOTP) para confirmar:');
|
|
211
324
|
if (!code) {
|
|
212
325
|
log.error('Código MFA não fornecido — operação cancelada.');
|
|
213
326
|
safeExit(1);
|
|
@@ -237,13 +350,9 @@ export function isMfaRequiredError(error) {
|
|
|
237
350
|
export async function withStepUpRetry(opts, doRequest, onError,
|
|
238
351
|
/** Chamado antes do prompt TOTP do retry (ex.: parar o spinner). */
|
|
239
352
|
beforePrompt) {
|
|
240
|
-
|
|
241
|
-
const
|
|
242
|
-
const
|
|
243
|
-
if (code)
|
|
244
|
-
first['X-Neetru-MFA-Token'] = code;
|
|
245
|
-
else if (savedSession)
|
|
246
|
-
first['X-Neetru-MFA-Session'] = savedSession;
|
|
353
|
+
// Mesma precedência do `resolveStepUp` (A8): código explícito, depois sessão.
|
|
354
|
+
const first = nonInteractiveStepUp(opts);
|
|
355
|
+
const code = first['X-Neetru-MFA-Token'];
|
|
247
356
|
let firstError;
|
|
248
357
|
try {
|
|
249
358
|
return await doRequest(first);
|
|
@@ -20,17 +20,21 @@ export declare function resolveDbConfig(engine: string): ComposeDbConfig | null;
|
|
|
20
20
|
export interface ComposeGeneratorInput {
|
|
21
21
|
productSlug: string;
|
|
22
22
|
dbEngine: string;
|
|
23
|
-
appPort?: number;
|
|
24
|
-
coreUrl?: string;
|
|
25
|
-
firebaseProject?: string;
|
|
26
|
-
firebaseApiKey?: string;
|
|
27
23
|
}
|
|
28
24
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
25
|
+
* URL de conexão do host (onde o app roda com `npm run dev`) para o banco do
|
|
26
|
+
* compose. `null` quando a engine não usa URL (Firestore usa o emulador).
|
|
31
27
|
*/
|
|
32
|
-
export declare function
|
|
28
|
+
export declare function localDatabaseUrl(dbEngine: string): string | null;
|
|
33
29
|
/**
|
|
34
|
-
*
|
|
30
|
+
* Gera o conteúdo do `neetru-compose.dev.yml` baseado na config do produto.
|
|
31
|
+
*
|
|
32
|
+
* Só o BANCO sobe em container. O agente ficou de fora de propósito
|
|
33
|
+
* (2026-10-09): o serviço `agent` antigo dependia de um `Dockerfile.agent` que
|
|
34
|
+
* nenhum caminho do `dev up` gravava (o compose falhava no build e nem o banco
|
|
35
|
+
* subia), rodava o binário do agente com `node` (é executável `pkg`, não JS) e
|
|
36
|
+
* ligava um `NEETRU_DEV_MODE` que o agente não implementa — além de montar o
|
|
37
|
+
* `docker.sock` do host num binário baixado. O agente local volta quando a
|
|
38
|
+
* sprint dev-suite entregar o modo dev no próprio agente.
|
|
35
39
|
*/
|
|
36
|
-
export declare function
|
|
40
|
+
export declare function generateComposeDev(input: ComposeGeneratorInput): string;
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import * as fs from 'node:fs';
|
|
2
|
-
import * as path from 'node:path';
|
|
3
1
|
/**
|
|
4
2
|
* Mapeia engine de banco → config Docker Compose.
|
|
5
3
|
* Usa imagens oficiais — mesmas engines que rodam em produção na VM.
|
|
@@ -57,12 +55,35 @@ export function resolveDbConfig(engine) {
|
|
|
57
55
|
return configs['vm-postgres-single'] ?? null; // default
|
|
58
56
|
}
|
|
59
57
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
58
|
+
* URL de conexão do host (onde o app roda com `npm run dev`) para o banco do
|
|
59
|
+
* compose. `null` quando a engine não usa URL (Firestore usa o emulador).
|
|
60
|
+
*/
|
|
61
|
+
export function localDatabaseUrl(dbEngine) {
|
|
62
|
+
const db = resolveDbConfig(dbEngine) ?? resolveDbConfig('vm-postgres-single');
|
|
63
|
+
switch (db.internalPort) {
|
|
64
|
+
case 5432:
|
|
65
|
+
return `postgresql://postgres:neetru_dev@localhost:${db.port}/app`;
|
|
66
|
+
case 3306:
|
|
67
|
+
return `mysql://root:neetru_dev@localhost:${db.port}/app`;
|
|
68
|
+
case 27017:
|
|
69
|
+
return `mongodb://localhost:${db.port}/app`;
|
|
70
|
+
default:
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Gera o conteúdo do `neetru-compose.dev.yml` baseado na config do produto.
|
|
76
|
+
*
|
|
77
|
+
* Só o BANCO sobe em container. O agente ficou de fora de propósito
|
|
78
|
+
* (2026-10-09): o serviço `agent` antigo dependia de um `Dockerfile.agent` que
|
|
79
|
+
* nenhum caminho do `dev up` gravava (o compose falhava no build e nem o banco
|
|
80
|
+
* subia), rodava o binário do agente com `node` (é executável `pkg`, não JS) e
|
|
81
|
+
* ligava um `NEETRU_DEV_MODE` que o agente não implementa — além de montar o
|
|
82
|
+
* `docker.sock` do host num binário baixado. O agente local volta quando a
|
|
83
|
+
* sprint dev-suite entregar o modo dev no próprio agente.
|
|
62
84
|
*/
|
|
63
85
|
export function generateComposeDev(input) {
|
|
64
86
|
const db = resolveDbConfig(input.dbEngine) ?? resolveDbConfig('vm-postgres-single');
|
|
65
|
-
const appPort = input.appPort ?? 3000;
|
|
66
87
|
// Bloco `environment:` só entra quando há vars — senão vira `environment:`
|
|
67
88
|
// vazio, que o docker compose rejeita ("environment must be a mapping").
|
|
68
89
|
// Firestore (env: {}) caía nisso → `dev up` firestore gerava compose inválido.
|
|
@@ -76,8 +97,9 @@ export function generateComposeDev(input) {
|
|
|
76
97
|
` timeout: ${db.healthcheck.timeout}`,
|
|
77
98
|
` retries: ${db.healthcheck.retries}`,
|
|
78
99
|
].join('\n');
|
|
79
|
-
return `# Neetru Dev Local —
|
|
100
|
+
return `# Neetru Dev Local — banco do produto ${input.productSlug} (${db.engine})
|
|
80
101
|
# Gerado por \`neetru dev up\`. Modifique o neetru.config.json e rode novamente.
|
|
102
|
+
# O app roda fora do container, com \`npm run dev\`.
|
|
81
103
|
|
|
82
104
|
services:
|
|
83
105
|
database:
|
|
@@ -90,63 +112,9 @@ ${dbEnvBlock} ports:
|
|
|
90
112
|
healthcheck:
|
|
91
113
|
${dbHealthcheck}
|
|
92
114
|
restart: unless-stopped
|
|
93
|
-
networks:
|
|
94
|
-
- neetru-dev-net
|
|
95
|
-
|
|
96
|
-
agent:
|
|
97
|
-
build:
|
|
98
|
-
context: .
|
|
99
|
-
dockerfile: Dockerfile.agent
|
|
100
|
-
container_name: neetru-dev-agent
|
|
101
|
-
environment:
|
|
102
|
-
- NEETRU_SERVER_ID=dev-local-${input.productSlug}
|
|
103
|
-
- NEETRU_CORE_URL=${input.coreUrl ?? 'https://core.neetru.com'}
|
|
104
|
-
- NEETRU_FIREBASE_PROJECT=${input.firebaseProject ?? 'neetru'}
|
|
105
|
-
- NEETRU_FIREBASE_API_KEY=${input.firebaseApiKey ?? ''}
|
|
106
|
-
- NEETRU_DEV_MODE=true
|
|
107
|
-
- NEETRU_APP_PORT=${appPort}
|
|
108
|
-
- DATABASE_URL=${db.internalPort === 5432 ? 'postgresql://postgres:neetru_dev@database:5432/app' : db.internalPort === 3306 ? 'mysql://root:neetru_dev@database:3306/app' : db.internalPort === 27017 ? 'mongodb://database:27017/app' : ''}
|
|
109
|
-
ports:
|
|
110
|
-
- "${appPort}:${appPort}"
|
|
111
|
-
volumes:
|
|
112
|
-
- /var/run/docker.sock:/var/run/docker.sock
|
|
113
|
-
- neetru-agent-data:/var/cache/neetru
|
|
114
|
-
- .:/app/product:cached
|
|
115
|
-
depends_on:
|
|
116
|
-
database:
|
|
117
|
-
condition: service_healthy
|
|
118
|
-
restart: unless-stopped
|
|
119
|
-
networks:
|
|
120
|
-
- neetru-dev-net
|
|
121
115
|
|
|
122
116
|
volumes:
|
|
123
117
|
neetru-db-data:
|
|
124
|
-
neetru-agent-data:
|
|
125
|
-
|
|
126
|
-
networks:
|
|
127
|
-
neetru-dev-net:
|
|
128
|
-
driver: bridge
|
|
129
118
|
`;
|
|
130
119
|
}
|
|
131
|
-
/**
|
|
132
|
-
* Escreve o compose + Dockerfile.agent no diretório do projeto.
|
|
133
|
-
*/
|
|
134
|
-
export function writeComposeDev(cwd, input) {
|
|
135
|
-
const composePath = path.join(cwd, 'neetru-compose.dev.yml');
|
|
136
|
-
const dockerfilePath = path.join(cwd, 'Dockerfile.agent');
|
|
137
|
-
const entrypointPath = path.join(cwd, 'agent-entrypoint.sh');
|
|
138
|
-
const compose = generateComposeDev(input);
|
|
139
|
-
fs.writeFileSync(composePath, compose, 'utf8');
|
|
140
|
-
// Copia o Dockerfile.agent do template embutido
|
|
141
|
-
const templateDir = path.join(path.dirname(new URL(import.meta.url).pathname), '..', '..', 'templates', 'dev');
|
|
142
|
-
// Em modo pkg/compilado, busca do __dirname ou do diretório do CLI
|
|
143
|
-
const altTemplate = path.join(process.cwd(), 'node_modules', '@neetru', 'cli', 'templates', 'dev');
|
|
144
|
-
const dockerfileSrc = fs.existsSync(path.join(templateDir, 'Dockerfile.agent'))
|
|
145
|
-
? path.join(templateDir, 'Dockerfile.agent')
|
|
146
|
-
: path.join(altTemplate, 'Dockerfile.agent');
|
|
147
|
-
if (fs.existsSync(dockerfileSrc)) {
|
|
148
|
-
fs.copyFileSync(dockerfileSrc, dockerfilePath);
|
|
149
|
-
}
|
|
150
|
-
return composePath;
|
|
151
|
-
}
|
|
152
120
|
//# sourceMappingURL=compose-generator.js.map
|
|
@@ -89,16 +89,43 @@ export declare const neetruConfigSchema: z.ZodObject<{
|
|
|
89
89
|
engine?: "firestore-instance" | "vm-postgres-single" | "vm-mysql-single" | "nosql-vm" | undefined;
|
|
90
90
|
dbId?: string | undefined;
|
|
91
91
|
}>>;
|
|
92
|
+
/** Protocolo de docs de produto v1 (`neetru docs init` grava; ver lib/product-docs/config.ts). */
|
|
93
|
+
docs: z.ZodOptional<z.ZodObject<{
|
|
94
|
+
protocolVersion: z.ZodOptional<z.ZodNumber>;
|
|
95
|
+
root: z.ZodOptional<z.ZodString>;
|
|
96
|
+
publish: z.ZodOptional<z.ZodBoolean>;
|
|
97
|
+
publishOnDeploy: z.ZodOptional<z.ZodBoolean>;
|
|
98
|
+
api: z.ZodOptional<z.ZodBoolean>;
|
|
99
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
100
|
+
protocolVersion: z.ZodOptional<z.ZodNumber>;
|
|
101
|
+
root: z.ZodOptional<z.ZodString>;
|
|
102
|
+
publish: z.ZodOptional<z.ZodBoolean>;
|
|
103
|
+
publishOnDeploy: z.ZodOptional<z.ZodBoolean>;
|
|
104
|
+
api: z.ZodOptional<z.ZodBoolean>;
|
|
105
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
106
|
+
protocolVersion: z.ZodOptional<z.ZodNumber>;
|
|
107
|
+
root: z.ZodOptional<z.ZodString>;
|
|
108
|
+
publish: z.ZodOptional<z.ZodBoolean>;
|
|
109
|
+
publishOnDeploy: z.ZodOptional<z.ZodBoolean>;
|
|
110
|
+
api: z.ZodOptional<z.ZodBoolean>;
|
|
111
|
+
}, z.ZodTypeAny, "passthrough">>>;
|
|
92
112
|
}, "strip", z.ZodTypeAny, {
|
|
93
113
|
name: string;
|
|
94
114
|
slug: string;
|
|
95
115
|
runtime: "nextjs" | "node-api";
|
|
96
116
|
$schema?: string | undefined;
|
|
97
|
-
tenantId?: string | undefined;
|
|
98
117
|
deploy?: z.objectOutputType<{
|
|
99
118
|
region: z.ZodOptional<z.ZodString>;
|
|
100
119
|
serviceName: z.ZodOptional<z.ZodString>;
|
|
101
120
|
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
121
|
+
tenantId?: string | undefined;
|
|
122
|
+
docs?: z.objectOutputType<{
|
|
123
|
+
protocolVersion: z.ZodOptional<z.ZodNumber>;
|
|
124
|
+
root: z.ZodOptional<z.ZodString>;
|
|
125
|
+
publish: z.ZodOptional<z.ZodBoolean>;
|
|
126
|
+
publishOnDeploy: z.ZodOptional<z.ZodBoolean>;
|
|
127
|
+
api: z.ZodOptional<z.ZodBoolean>;
|
|
128
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
102
129
|
publish?: {
|
|
103
130
|
description: string;
|
|
104
131
|
status: "beta" | "soon" | "live";
|
|
@@ -117,11 +144,18 @@ export declare const neetruConfigSchema: z.ZodObject<{
|
|
|
117
144
|
slug: string;
|
|
118
145
|
runtime: "nextjs" | "node-api";
|
|
119
146
|
$schema?: string | undefined;
|
|
120
|
-
tenantId?: string | undefined;
|
|
121
147
|
deploy?: z.objectInputType<{
|
|
122
148
|
region: z.ZodOptional<z.ZodString>;
|
|
123
149
|
serviceName: z.ZodOptional<z.ZodString>;
|
|
124
150
|
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
151
|
+
tenantId?: string | undefined;
|
|
152
|
+
docs?: z.objectInputType<{
|
|
153
|
+
protocolVersion: z.ZodOptional<z.ZodNumber>;
|
|
154
|
+
root: z.ZodOptional<z.ZodString>;
|
|
155
|
+
publish: z.ZodOptional<z.ZodBoolean>;
|
|
156
|
+
publishOnDeploy: z.ZodOptional<z.ZodBoolean>;
|
|
157
|
+
api: z.ZodOptional<z.ZodBoolean>;
|
|
158
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
125
159
|
publish?: {
|
|
126
160
|
description: string;
|
|
127
161
|
status: "beta" | "soon" | "live";
|
|
@@ -42,6 +42,17 @@ export const neetruConfigSchema = z.object({
|
|
|
42
42
|
engine: z.enum(['vm-postgres-single', 'vm-mysql-single', 'nosql-vm', 'firestore-instance']).optional(),
|
|
43
43
|
dbId: z.string().optional(),
|
|
44
44
|
}).optional(),
|
|
45
|
+
/** Protocolo de docs de produto v1 (`neetru docs init` grava; ver lib/product-docs/config.ts). */
|
|
46
|
+
docs: z
|
|
47
|
+
.object({
|
|
48
|
+
protocolVersion: z.number().int().positive().optional(),
|
|
49
|
+
root: z.string().optional(),
|
|
50
|
+
publish: z.boolean().optional(),
|
|
51
|
+
publishOnDeploy: z.boolean().optional(),
|
|
52
|
+
api: z.boolean().optional(),
|
|
53
|
+
})
|
|
54
|
+
.passthrough()
|
|
55
|
+
.optional(),
|
|
45
56
|
});
|
|
46
57
|
export const catalogUpsertPayloadSchema = z.object({
|
|
47
58
|
slug: slugSchema,
|