@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
package/dist/commands/doctor.js
CHANGED
|
@@ -25,7 +25,13 @@ import { log } from '../utils/logger.js';
|
|
|
25
25
|
// Fix do bug onde 2.0.0 ficava hardcoded depois de bumps.
|
|
26
26
|
import { CLI_VERSION } from '../version.js';
|
|
27
27
|
import { safeExit } from '../utils/safe-exit.js';
|
|
28
|
+
import { RUNTIME_ENVIRONMENT_IDS, TENANT_ENVIRONMENT_IDS } from '../lib/envs.js';
|
|
28
29
|
const NPM_REGISTRY = 'https://registry.npmjs.org/@neetru/cli';
|
|
30
|
+
/**
|
|
31
|
+
* `NEETRU_ENV` que o doctor ainda aceita sem estar em alfabeto nenhum — legado
|
|
32
|
+
* declarado (ver `checkNeetruEnv`), candidato a deprecação.
|
|
33
|
+
*/
|
|
34
|
+
const NEETRU_ENV_LEGADOS = ['beta'];
|
|
29
35
|
/* ── Checks individuais — exportados pra teste ────────────────────── */
|
|
30
36
|
export async function checkToken() {
|
|
31
37
|
const t = getActiveTokenSync();
|
|
@@ -92,7 +98,36 @@ export async function checkConfigSchema(cwd) {
|
|
|
92
98
|
export async function checkNeetruEnv(cwd) {
|
|
93
99
|
// bug: 'production' não é valor canônico do SDK/Core — o correto é 'prod'.
|
|
94
100
|
// 'production' causava doctor OK mas runtime falhava ao comparar NEETRU_ENV.
|
|
95
|
-
|
|
101
|
+
// 2026-10-12: a lista rejeitava `dev-local`, que o Core INJETA.
|
|
102
|
+
//
|
|
103
|
+
// O Core grava `NEETRU_ENV = environmentId` no deploy
|
|
104
|
+
// (`_vm-deploy-readiness.ts:9` e `:76`), e `environmentId` só pode ser
|
|
105
|
+
// `dev-local`, `staging` ou `prod` (`ENVIRONMENT_IDS`, schemas/envs.ts:39).
|
|
106
|
+
// Com `dev-local` fora desta lista, o doctor reprovava com exit 1 uma
|
|
107
|
+
// configuração que o próprio Core tinha acabado de escrever — e em CI isso
|
|
108
|
+
// quebra o build sobre uma config correta.
|
|
109
|
+
//
|
|
110
|
+
// `staging` entra aqui pelo mesmo motivo (o Core o produz), mas com uma
|
|
111
|
+
// ressalva REGISTRADA e não resolvida: o tipo `NeetruEnv` do SDK
|
|
112
|
+
// (`src/types.ts:873`) lista `dev | workspace | prod | dev-local` e NÃO
|
|
113
|
+
// inclui `staging`. Procurei o guard de runtime (`resolveNeetruEnv`) e ele
|
|
114
|
+
// não existe no `dist` publicado do SDK — só é citado na doc e no código de
|
|
115
|
+
// deploy do Core. Então NÃO consegui confirmar se `staging` quebra em
|
|
116
|
+
// runtime. O doctor para de reprovar (o Core produz esse valor), e a dúvida
|
|
117
|
+
// fica anotada em vez de virar silêncio nos dois sentidos.
|
|
118
|
+
//
|
|
119
|
+
// `workspace` e `beta` ficam por compatibilidade: estavam aceitos antes e
|
|
120
|
+
// remover valor de uma lista de validação quebra quem já configurou. `beta`
|
|
121
|
+
// não aparece em nenhum alfabeto atual — candidato a deprecação declarada,
|
|
122
|
+
// não a remoção silenciosa.
|
|
123
|
+
//
|
|
124
|
+
// P105: a lista era escrita à mão. Agora é a UNIÃO das duas fontes — o
|
|
125
|
+
// `NEETRU_ENV` do SDK (`RUNTIME_ENVIRONMENT_IDS`) e o `environmentId` que o
|
|
126
|
+
// Core injeta (`TENANT_ENVIRONMENT_IDS`) — mais o legado declarado abaixo.
|
|
127
|
+
// Mesmo conjunto de antes; só a ordem do texto "esperado …" mudou.
|
|
128
|
+
const valid = [
|
|
129
|
+
...new Set([...RUNTIME_ENVIRONMENT_IDS, ...TENANT_ENVIRONMENT_IDS, ...NEETRU_ENV_LEGADOS]),
|
|
130
|
+
];
|
|
96
131
|
// Procura .env.local pra ver NEETRU_ENV.
|
|
97
132
|
try {
|
|
98
133
|
const raw = await fs.readFile(path.join(cwd, '.env.local'), 'utf8');
|
package/dist/commands/domains.js
CHANGED
|
@@ -53,6 +53,56 @@ function outcomeColor(outcome) {
|
|
|
53
53
|
default: return chalk.dim(outcome);
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Texto plain PT-BR do motivo de um `outcome: 'skipped'` (bug_6e9fe576).
|
|
58
|
+
* `stage_sem_subdominio`/`subdomain_cloud_run_unsupported` são esperados
|
|
59
|
+
* (dev-local e produto Cloud Run nunca têm domínio por VM); os outros dois
|
|
60
|
+
* exigem ação de quem pediu o reconcile. `undefined` cobre o Core anterior
|
|
61
|
+
* ao #677, que nunca manda `reason` — nesse caso dizemos isso explicitamente
|
|
62
|
+
* em vez de deixar a célula vazia (o ponto do bug original era exatamente
|
|
63
|
+
* "pulei e não disse por quê").
|
|
64
|
+
*/
|
|
65
|
+
function skipReasonText(reason) {
|
|
66
|
+
switch (reason) {
|
|
67
|
+
case 'stage_sem_subdominio':
|
|
68
|
+
return 'ambiente local, sem domínio público (esperado)';
|
|
69
|
+
case 'subdomain_cloud_run_unsupported':
|
|
70
|
+
return 'produto Cloud Run, não usa domínio por VM (esperado)';
|
|
71
|
+
case 'subdomain_deploy_config_missing':
|
|
72
|
+
return 'ambiente sem configuração de deploy — corrija o ambiente';
|
|
73
|
+
case 'subdomain_hard_cap_reached':
|
|
74
|
+
return 'limite de subdomínios atingido — requer ação do operador';
|
|
75
|
+
default:
|
|
76
|
+
return 'motivo não informado por este Core (atualize o Core para ver detalhes)';
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** Célula da coluna "Motivo/erro" — reason em pulados, err em erros, vazio nos demais. */
|
|
80
|
+
function reconcileNote(r) {
|
|
81
|
+
if (r.outcome === 'skipped')
|
|
82
|
+
return skipReasonText(r.reason);
|
|
83
|
+
if (r.outcome === 'error')
|
|
84
|
+
return r.err ?? '';
|
|
85
|
+
return '';
|
|
86
|
+
}
|
|
87
|
+
/** Pulados que exigem ação de quem pediu o reconcile (os outros dois são esperados). */
|
|
88
|
+
const SKIP_EXIGE_ACAO = new Set([
|
|
89
|
+
'subdomain_deploy_config_missing',
|
|
90
|
+
'subdomain_hard_cap_reached',
|
|
91
|
+
]);
|
|
92
|
+
/**
|
|
93
|
+
* A execução teve erro? Olha a contagem `errors` ALÉM do `ok` do Core: o Core
|
|
94
|
+
* anterior ao #677 manda `ok: true` FIXO mesmo com erro (é o próprio
|
|
95
|
+
* bug_6e9fe576), e a CLI publicada conversa com ele até o deploy. Decidir só
|
|
96
|
+
* pelo `ok` reabria a mentira: "Erros: 1" seguido de "tudo já existe" com
|
|
97
|
+
* exit 0 (revisão do cli#80).
|
|
98
|
+
*/
|
|
99
|
+
function reconcileFalhou(resp) {
|
|
100
|
+
return resp.ok === false || resp.errors > 0;
|
|
101
|
+
}
|
|
102
|
+
/** Ambientes pulados por um motivo que exige ação (só o Core #677+ informa o motivo). */
|
|
103
|
+
function pendentesDeAcao(resp) {
|
|
104
|
+
return resp.details.filter((r) => r.outcome === 'skipped' && r.reason !== undefined && SKIP_EXIGE_ACAO.has(r.reason));
|
|
105
|
+
}
|
|
56
106
|
export async function runDomainsList(opts) {
|
|
57
107
|
if (!opts.product) {
|
|
58
108
|
const msg = '--product <slug> é obrigatório.';
|
|
@@ -95,7 +145,7 @@ export async function runDomainsList(opts) {
|
|
|
95
145
|
{ header: 'Cert', value: (r) => certStatusColor(r.certStatus), maxWidth: 18 },
|
|
96
146
|
{ header: 'Alvo', value: (r) => r.targetKind ?? '—', maxWidth: 14 },
|
|
97
147
|
{ header: 'Porta', value: (r) => r.upstreamPort != null ? String(r.upstreamPort) : '—', maxWidth: 8 },
|
|
98
|
-
{ header: 'VM', value: (r) => r.serverId ?? '—',
|
|
148
|
+
{ header: 'VM', value: (r) => r.serverId ?? '—', identificador: true },
|
|
99
149
|
{ header: 'Atualizado', value: (r) => fmtTimestamp(r.updatedAt), maxWidth: 20 },
|
|
100
150
|
], resp.subdomains);
|
|
101
151
|
}
|
|
@@ -127,8 +177,15 @@ export async function runDomainsReconcile(opts) {
|
|
|
127
177
|
spinner?.fail('Falha ao reconciliar domínios.');
|
|
128
178
|
handleApiError(err, opts.json);
|
|
129
179
|
}
|
|
180
|
+
// bug_6e9fe576: `ok:false` é o Core sinalizando que a execução teve erro
|
|
181
|
+
// real (não é exceção de rede/HTTP — a resposta é 200, o resumo que reporta
|
|
182
|
+
// a falha). Trata igual ao resto da CLI que agrega um resultado em lote
|
|
183
|
+
// (`doctor`/`smoke`): --json imprime o corpo e sai já com o código certo,
|
|
184
|
+
// sem cair nos prints humanos abaixo.
|
|
130
185
|
if (opts.json) {
|
|
131
186
|
console.log(JSON.stringify(resp));
|
|
187
|
+
if (reconcileFalhou(resp) || pendentesDeAcao(resp).length > 0)
|
|
188
|
+
safeExit(1);
|
|
132
189
|
return;
|
|
133
190
|
}
|
|
134
191
|
log.heading(`Reconcile — "${chalk.bold(resp.productSlug)}"`);
|
|
@@ -147,15 +204,39 @@ export async function runDomainsReconcile(opts) {
|
|
|
147
204
|
{ header: 'Resultado', value: (r) => outcomeColor(r.outcome), maxWidth: 12 },
|
|
148
205
|
{ header: 'FQDN', value: (r) => r.fqdn || '—', maxWidth: 44 },
|
|
149
206
|
{ header: 'Status', value: (r) => subdomainStatusColor(r.status), maxWidth: 18 },
|
|
150
|
-
{ header: '
|
|
207
|
+
{ header: 'Motivo/erro', value: reconcileNote, maxWidth: 46 },
|
|
151
208
|
], resp.details);
|
|
152
209
|
}
|
|
210
|
+
// bug_6e9fe576: "Todos os domínios obrigatórios já existem." era impresso
|
|
211
|
+
// mesmo com `skipped > 0` — dois ambientes target=workspace, nada criado,
|
|
212
|
+
// nada existente, e a CLI dizia que tudo estava ok. Agora a frase de
|
|
213
|
+
// sucesso-sem-criação só sai quando NADA foi pulado; com pulados, aponta
|
|
214
|
+
// pra tabela acima (que já tem o motivo, com ou sem `reason` do Core).
|
|
215
|
+
const falhou = reconcileFalhou(resp);
|
|
216
|
+
const exigeAcao = pendentesDeAcao(resp);
|
|
153
217
|
if (resp.created > 0) {
|
|
154
218
|
log.success(`${resp.created} subdomínio(s) criado(s). Execute \`neetru domains list --product ${opts.product}\` para ver o status.`);
|
|
155
219
|
}
|
|
156
|
-
|
|
157
|
-
log.
|
|
220
|
+
if (falhou) {
|
|
221
|
+
log.error('Reconcile encontrou erro(s). Veja os detalhes acima.');
|
|
158
222
|
}
|
|
223
|
+
if (exigeAcao.length > 0) {
|
|
224
|
+
const quais = exigeAcao.map((r) => r.envType).join(', ');
|
|
225
|
+
log.warn(`${exigeAcao.length} ambiente(s) precisam de ação (${quais}) — o domínio não foi garantido. Veja o motivo na tabela acima.`);
|
|
226
|
+
}
|
|
227
|
+
if (resp.created === 0 && !falhou && exigeAcao.length === 0) {
|
|
228
|
+
if (resp.skipped > 0) {
|
|
229
|
+
log.warn(`Nenhum domínio criado — ${resp.skipped} ambiente(s) pulado(s). Veja o motivo na tabela acima.`);
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
log.success('Todos os domínios obrigatórios já existem.');
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// Exit 1 quando houve erro (pela contagem local, não só pelo `ok` do Core) ou
|
|
236
|
+
// quando um ambiente ficou sem domínio por um motivo que exige ação — como o
|
|
237
|
+
// doctor/smoke, que derivam o exit do resultado que a própria CLI conta.
|
|
238
|
+
if (falhou || exigeAcao.length > 0)
|
|
239
|
+
safeExit(1);
|
|
159
240
|
}
|
|
160
241
|
export async function runDomainsRetry(opts) {
|
|
161
242
|
if (!opts.product) {
|
package/dist/commands/env.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { type RuntimeEnvironmentId } from '../lib/envs.js';
|
|
2
|
+
/**
|
|
3
|
+
* O `NEETRU_ENV` do SDK sai da tabela `VOCABULARIOS_DE_AMBIENTE` (`lib/envs.ts`,
|
|
4
|
+
* P105) — era `['dev','workspace','prod']` escrito à mão — mais o apelido
|
|
5
|
+
* `production`, aceito na entrada e gravado como `prod`.
|
|
6
|
+
*/
|
|
7
|
+
declare const APELIDO_PRODUCTION = "production";
|
|
8
|
+
export type EnvTarget = RuntimeEnvironmentId | typeof APELIDO_PRODUCTION;
|
|
9
|
+
type StoredEnvTarget = RuntimeEnvironmentId;
|
|
4
10
|
export interface EnvSwitchOptions {
|
|
5
11
|
target: string;
|
|
6
12
|
cwd?: string;
|
package/dist/commands/env.js
CHANGED
|
@@ -8,7 +8,15 @@ import * as fs from 'node:fs/promises';
|
|
|
8
8
|
import * as fsSync from 'node:fs';
|
|
9
9
|
import * as path from 'node:path';
|
|
10
10
|
import { log } from '../utils/logger.js';
|
|
11
|
-
|
|
11
|
+
import { problemaDeCodificacao, recusaDoEnvSwitch } from '../lib/texto-utf8.js';
|
|
12
|
+
import { RUNTIME_ENVIRONMENT_IDS } from '../lib/envs.js';
|
|
13
|
+
/**
|
|
14
|
+
* O `NEETRU_ENV` do SDK sai da tabela `VOCABULARIOS_DE_AMBIENTE` (`lib/envs.ts`,
|
|
15
|
+
* P105) — era `['dev','workspace','prod']` escrito à mão — mais o apelido
|
|
16
|
+
* `production`, aceito na entrada e gravado como `prod`.
|
|
17
|
+
*/
|
|
18
|
+
const APELIDO_PRODUCTION = 'production';
|
|
19
|
+
const SUPPORTED = [...RUNTIME_ENVIRONMENT_IDS, APELIDO_PRODUCTION];
|
|
12
20
|
/**
|
|
13
21
|
* Normaliza um target de ambiente (aceita o alias `production` → `prod`) ou
|
|
14
22
|
* `null` se não reconhecido. Exportada (2026-07-22) pra `neetru build
|
|
@@ -18,7 +26,7 @@ const SUPPORTED = ['dev', 'workspace', 'prod', 'production'];
|
|
|
18
26
|
export function normalizeTarget(t) {
|
|
19
27
|
if (!SUPPORTED.includes(t))
|
|
20
28
|
return null;
|
|
21
|
-
return t ===
|
|
29
|
+
return t === APELIDO_PRODUCTION ? 'prod' : t;
|
|
22
30
|
}
|
|
23
31
|
/**
|
|
24
32
|
* Substitui ou adiciona `NEETRU_ENV=<value>` em `content` (texto do .env).
|
|
@@ -60,7 +68,19 @@ export async function runEnvSwitch(opts) {
|
|
|
60
68
|
const filePath = path.join(cwd, file);
|
|
61
69
|
let content = '';
|
|
62
70
|
if (fsSync.existsSync(filePath)) {
|
|
63
|
-
|
|
71
|
+
// Rodada final 2 do cli#81 (BAIXA): `readFile(…, 'utf-8')` trocava cada
|
|
72
|
+
// byte que não é UTF-8 por U+FFFD, e a regravação abaixo levava a troca ao
|
|
73
|
+
// disco — um ANSI com `Café` terminava `Caf\uFFFD`, com exit 0 e "✓".
|
|
74
|
+
// Agora lê em bytes e recusa ANTES de gravar o que a regravação estragaria.
|
|
75
|
+
const bruto = await fs.readFile(filePath);
|
|
76
|
+
const problema = problemaDeCodificacao(bruto);
|
|
77
|
+
if (problema === 'utf16' || problema === 'nao-utf8') {
|
|
78
|
+
log.error(recusaDoEnvSwitch(file, problema).message);
|
|
79
|
+
safeExit(1);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
// A marca BOM fica no texto e volta ao disco como estava.
|
|
83
|
+
content = bruto.toString('utf8');
|
|
64
84
|
}
|
|
65
85
|
const updated = applyEnvSwitch(content, storedTarget);
|
|
66
86
|
await fs.writeFile(filePath, updated, 'utf-8');
|
|
@@ -68,7 +68,7 @@ export async function runHostingList(opts) {
|
|
|
68
68
|
}
|
|
69
69
|
renderTable([
|
|
70
70
|
{ header: 'HOST', value: (d) => d.host ?? '—', maxWidth: 32 },
|
|
71
|
-
{ header: 'TENANT', value: (d) => d.tenantId ?? '—',
|
|
71
|
+
{ header: 'TENANT', value: (d) => d.tenantId ?? '—', identificador: true },
|
|
72
72
|
{ header: 'STATUS', value: (d) => d.status ?? '—' },
|
|
73
73
|
{ header: 'CERT', value: (d) => d.certStatus ?? '—' },
|
|
74
74
|
{ header: 'TARGET', value: (d) => d.targetService ?? '—', maxWidth: 24 },
|
|
@@ -98,7 +98,7 @@ export async function runBuildsList(opts) {
|
|
|
98
98
|
}
|
|
99
99
|
log.heading(`Cloud Builds (${res.builds.length})`);
|
|
100
100
|
renderTable([
|
|
101
|
-
{ header: 'ID', value: (b) => b.id,
|
|
101
|
+
{ header: 'ID', value: (b) => b.id, identificador: true },
|
|
102
102
|
{ header: 'STATUS', value: (b) => b.status },
|
|
103
103
|
{ header: 'REGIÃO', value: (b) => b.region ?? 'global' },
|
|
104
104
|
{ header: 'SOURCE', value: (b) => b.source ?? '—', maxWidth: 28 },
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ interface InitOptions {
|
|
|
9
9
|
path?: string;
|
|
10
10
|
/** Modo non-interactive — sai com erro se prompt for necessário. */
|
|
11
11
|
yes?: boolean;
|
|
12
|
+
/** Não roda `neetru docs init` depois do scaffold (protocolo de docs v1). */
|
|
13
|
+
semDocs?: boolean;
|
|
12
14
|
}
|
|
13
15
|
export declare function runInit(opts: InitOptions): Promise<void>;
|
|
14
16
|
export {};
|
package/dist/commands/init.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import * as fs from 'fs/promises';
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import ora from 'ora';
|
|
4
|
-
|
|
4
|
+
// `inquirer` NÃO é importado aqui: só o caminho interativo de `resolveTarget`
|
|
5
|
+
// pergunta, e ele o carrega na hora (P112, 2026-10-18). O import a frio do
|
|
6
|
+
// inquirer custava ~0,35 s sozinho e ~1,1 s com a suíte rodando — pago por
|
|
7
|
+
// todo `neetru init --yes` (CI e scripts) e pelo 1º teste do init.test.ts,
|
|
8
|
+
// que estourava o timeout de 10 s com a máquina carregada.
|
|
5
9
|
import { log } from '../utils/logger.js';
|
|
6
10
|
import { safeExit } from '../utils/safe-exit.js';
|
|
7
11
|
/**
|
|
@@ -81,6 +85,8 @@ async function resolveTarget(name, cwd, opts) {
|
|
|
81
85
|
return { dir: subDir, mode: 'new', force: false };
|
|
82
86
|
}
|
|
83
87
|
// ── Interactive ──────────────────────────────────────────────────────
|
|
88
|
+
// Só aqui há pergunta: o inquirer é carregado agora (ver o topo do arquivo).
|
|
89
|
+
const { default: inquirer } = await import('inquirer');
|
|
84
90
|
console.log();
|
|
85
91
|
log.info(`Onde você quer inicializar o projeto "${name}"?`);
|
|
86
92
|
console.log();
|
|
@@ -271,6 +277,13 @@ export async function runInit(opts) {
|
|
|
271
277
|
},
|
|
272
278
|
}, null, 2));
|
|
273
279
|
spinner.succeed(mode === 'merge' ? 'Scaffold mesclado!' : 'Projeto criado!');
|
|
280
|
+
// Protocolo de docs de produto v1 (2026-10-03): o produto nasce com o
|
|
281
|
+
// mínimo do primeiro dia (README, CHANGELOG, docs/…). Idempotente — em modo
|
|
282
|
+
// merge nunca sobrescreve doc existente. Falha aqui não derruba o init.
|
|
283
|
+
if (!opts.semDocs) {
|
|
284
|
+
const { initDocsAfterScaffold } = await import('./docs-produto.js');
|
|
285
|
+
await initDocsAfterScaffold(dir);
|
|
286
|
+
}
|
|
274
287
|
console.log();
|
|
275
288
|
log.info(`Diretório: ${dir}`);
|
|
276
289
|
log.info(`Modo: ${mode === 'merge' ? 'MESCLAR (preserva arquivos existentes)' : 'NOVO (scaffold completo)'}`);
|
package/dist/commands/login.js
CHANGED
|
@@ -21,6 +21,7 @@ import { spawn } from 'node:child_process';
|
|
|
21
21
|
import { config } from '../lib/config.js';
|
|
22
22
|
import { saveToken } from '../lib/auth.js';
|
|
23
23
|
import { apiRequest, CliApiError, CliNetworkError } from '../lib/api-client.js';
|
|
24
|
+
import { discardMfaSessionOfOtherUid } from '../lib/cli-write.js';
|
|
24
25
|
import { log } from '../utils/logger.js';
|
|
25
26
|
import { safeExit } from '../utils/safe-exit.js';
|
|
26
27
|
const TOKEN_PATTERN = /^nrt_[a-z0-9]{8,16}_[A-Za-z0-9_\-=]{20,64}$/;
|
|
@@ -51,28 +52,52 @@ function openBrowser(url) {
|
|
|
51
52
|
catch {
|
|
52
53
|
return; // URL inválida → não abre (caller já imprimiu pra copiar/colar)
|
|
53
54
|
}
|
|
55
|
+
// bug_d414f21c (medium): sem binário de abrir browser (ex.: WSL sem
|
|
56
|
+
// `xdg-open`), `spawn(...)` emite 'error' (ENOENT) ASSINCRONAMENTE — sem
|
|
57
|
+
// listener, o Node trata como exceção não capturada e derruba o processo,
|
|
58
|
+
// abortando o polling do device-code antes de começar. Registra o handler
|
|
59
|
+
// e avisa o usuário (ele já tem a URL impressa pra copiar/colar); nunca
|
|
60
|
+
// deixa esse erro propagar.
|
|
61
|
+
const warnFallback = () => {
|
|
62
|
+
log.warn('Não consegui abrir o navegador; abra a URL acima manualmente.');
|
|
63
|
+
};
|
|
54
64
|
try {
|
|
65
|
+
let child;
|
|
55
66
|
if (process.platform === 'win32') {
|
|
56
|
-
spawn('rundll32', ['url.dll,FileProtocolHandler', url], {
|
|
67
|
+
child = spawn('rundll32', ['url.dll,FileProtocolHandler', url], {
|
|
57
68
|
detached: true,
|
|
58
69
|
stdio: 'ignore',
|
|
59
70
|
windowsHide: true,
|
|
60
|
-
})
|
|
61
|
-
return;
|
|
71
|
+
});
|
|
62
72
|
}
|
|
63
|
-
if (process.platform === 'darwin') {
|
|
64
|
-
spawn('open', [url], { detached: true, stdio: 'ignore' })
|
|
65
|
-
|
|
73
|
+
else if (process.platform === 'darwin') {
|
|
74
|
+
child = spawn('open', [url], { detached: true, stdio: 'ignore' });
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
child = spawn('xdg-open', [url], { detached: true, stdio: 'ignore' });
|
|
66
78
|
}
|
|
67
|
-
|
|
79
|
+
child.on('error', warnFallback);
|
|
80
|
+
child.unref();
|
|
68
81
|
}
|
|
69
82
|
catch {
|
|
70
|
-
|
|
83
|
+
warnFallback();
|
|
71
84
|
}
|
|
72
85
|
}
|
|
73
86
|
function sleep(ms) {
|
|
74
87
|
return new Promise((res) => setTimeout(res, ms));
|
|
75
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* A8 (2026-10-13): o login trocava o Bearer mas mantinha o `mfa-session.json`
|
|
91
|
+
* da conta anterior. O Core só aceita sessão MFA do MESMO uid do Bearer, então
|
|
92
|
+
* por até 1h todo comando destrutivo da conta nova tomava 401. Sessão de outro
|
|
93
|
+
* uid sai junto com a troca de conta; a da mesma conta fica.
|
|
94
|
+
*/
|
|
95
|
+
async function discardForeignMfaSession(uid, json) {
|
|
96
|
+
if (await discardMfaSessionOfOtherUid(uid)) {
|
|
97
|
+
if (!json)
|
|
98
|
+
log.dim('Sessão MFA de 1h da conta anterior descartada (rode `neetru auth mfa-session` se precisar).');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
76
101
|
async function pollForToken(deviceCode, initialIntervalSec, expiresAtMs, json) {
|
|
77
102
|
let intervalMs = initialIntervalSec * 1000;
|
|
78
103
|
const spinner = json
|
|
@@ -143,6 +168,7 @@ export async function runLogin(opts = {}) {
|
|
|
143
168
|
const path = await saveToken(token, me.email);
|
|
144
169
|
// Compat: alguns comandos legados ainda leem do Conf.
|
|
145
170
|
config.set('neetruApiKey', token);
|
|
171
|
+
await discardForeignMfaSession(me.uid, json);
|
|
146
172
|
if (json) {
|
|
147
173
|
emitJson({ ok: true, email: me.email, role: me.role, path });
|
|
148
174
|
}
|
|
@@ -213,6 +239,7 @@ export async function runLogin(opts = {}) {
|
|
|
213
239
|
const path = await saveToken(accessToken, me.email);
|
|
214
240
|
// Compat: legacy commands podem usar Conf — mantemos o token lá também.
|
|
215
241
|
config.set('neetruApiKey', accessToken);
|
|
242
|
+
await discardForeignMfaSession(me.uid, json);
|
|
216
243
|
if (json) {
|
|
217
244
|
emitJson({ ok: true, email: me.email, role: me.role, path });
|
|
218
245
|
}
|
package/dist/commands/logs.js
CHANGED
|
@@ -10,9 +10,8 @@
|
|
|
10
10
|
import { existsSync, readFileSync, statSync, openSync, readSync, closeSync } from 'node:fs';
|
|
11
11
|
import { join } from 'node:path';
|
|
12
12
|
import chalk from 'chalk';
|
|
13
|
-
import { apiRequest, CliNetworkError } from '../lib/api-client.js';
|
|
13
|
+
import { apiRequest, CliNetworkError, resolveTrustedApiUrl } from '../lib/api-client.js';
|
|
14
14
|
import { handleApiError } from '../lib/api-error.js';
|
|
15
|
-
import { config } from '../lib/config.js';
|
|
16
15
|
import { getActiveTokenSync } from '../lib/token-resolver.js';
|
|
17
16
|
import { log } from '../utils/logger.js';
|
|
18
17
|
import { safeExit } from '../utils/safe-exit.js';
|
|
@@ -239,7 +238,6 @@ async function fetchLogs(clientId, params) {
|
|
|
239
238
|
async function runSseFollow(clientId, opts, jsonMode) {
|
|
240
239
|
// MASTER-HIGH-048 (2.11.0): SSE stream usa o mesmo resolver canonico.
|
|
241
240
|
const apiKey = getActiveTokenSync() ?? undefined;
|
|
242
|
-
const apiBase = config.get('apiBase') ?? 'https://api.neetru.com';
|
|
243
241
|
const qs = new URLSearchParams({ clientId });
|
|
244
242
|
if (opts.level)
|
|
245
243
|
qs.set('level', opts.level);
|
|
@@ -249,7 +247,17 @@ async function runSseFollow(clientId, opts, jsonMode) {
|
|
|
249
247
|
qs.set('channel', opts.channel);
|
|
250
248
|
if (opts.correlationId)
|
|
251
249
|
qs.set('correlationId', opts.correlationId);
|
|
252
|
-
|
|
250
|
+
// C7 (2026-10-13): a base e a guarda são as MESMAS do `apiRequest` (que fez o
|
|
251
|
+
// primeiro request deste comando). Antes o stream lia `config.get('apiBase')`
|
|
252
|
+
// — chave fora do schema — e mandava o Bearer pra qualquer host gravado ali,
|
|
253
|
+
// além de ignorar o `neetruApiUrl` de staging/local.
|
|
254
|
+
let streamUrl;
|
|
255
|
+
try {
|
|
256
|
+
streamUrl = resolveTrustedApiUrl(`/api/cli/v1/logs/stream?${qs.toString()}`);
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
handleApiError(error, jsonMode);
|
|
260
|
+
}
|
|
253
261
|
let attempts = 0;
|
|
254
262
|
const MAX_RECONNECTS = 5;
|
|
255
263
|
let lastEventId;
|
package/dist/commands/mobile.js
CHANGED
|
@@ -11,11 +11,12 @@
|
|
|
11
11
|
* GET /api/cli/v1/products/{slug}/mobile-apps — role admin|operator
|
|
12
12
|
* DELETE /api/cli/v1/products/{slug}/mobile-apps/{appId} — role admin ONLY + step-up MFA
|
|
13
13
|
*
|
|
14
|
-
* `redirectUri` PRECISA ser `https://` (Universal Link/App Link, RFC 8252)
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
14
|
+
* `redirectUri` PRECISA ser `https://` (Universal Link/App Link, RFC 8252)
|
|
15
|
+
* ou `http://localhost`/`http://127.0.0.1` (loopback de dev) — mesma regra
|
|
16
|
+
* do Core (`validateRedirectUris`). O Core rejeita custom scheme
|
|
17
|
+
* (`meuapp://`) com 400. Isso é decisão de segurança do owner, não
|
|
18
|
+
* limitação temporária — a CLI valida o mesmo localmente pra falhar rápido
|
|
19
|
+
* com mensagem clara, mas NUNCA oferece custom scheme como alternativa.
|
|
19
20
|
*
|
|
20
21
|
* O `id` retornado pelo Core é `<slug>__<platform>` — o app é PKCE público
|
|
21
22
|
* (Authorization Code + PKCE, sem client secret).
|
|
@@ -42,6 +43,28 @@ const MOBILE_JSON_REL = '.neetru/mobile.json';
|
|
|
42
43
|
function jsonError(message, error = 'error') {
|
|
43
44
|
console.log(JSON.stringify({ ok: false, error, message }));
|
|
44
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* bug_afcf958a (low): espelha EXATAMENTE a regra de `redirectUri` do Core
|
|
48
|
+
* (`_oidc-clients-core.ts` → `validateRedirectUris`, usada também pelo
|
|
49
|
+
* registro de apps mobile em `_product-mobile-apps-core.ts`): aceita
|
|
50
|
+
* `https://` ou `http://` com host `localhost`/`127.0.0.1` (loopback de
|
|
51
|
+
* dev, RFC 8252). NUNCA custom scheme (`meuapp://`) — isso o Core rejeita
|
|
52
|
+
* com 400, decisão de segurança do owner, e a CLI não pode ser MAIS
|
|
53
|
+
* permissiva que o servidor que vai validar de novo.
|
|
54
|
+
*/
|
|
55
|
+
function isAcceptableMobileRedirectUri(uri) {
|
|
56
|
+
let parsed;
|
|
57
|
+
try {
|
|
58
|
+
parsed = new URL(uri);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
if (parsed.protocol === 'https:')
|
|
64
|
+
return true;
|
|
65
|
+
return (parsed.protocol === 'http:' &&
|
|
66
|
+
(parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1'));
|
|
67
|
+
}
|
|
45
68
|
function mobileStatusColor(status) {
|
|
46
69
|
switch (status) {
|
|
47
70
|
case 'active': return chalk.green(status);
|
|
@@ -82,8 +105,9 @@ export async function runMobileInit(opts = {}) {
|
|
|
82
105
|
safeExit(1);
|
|
83
106
|
return;
|
|
84
107
|
}
|
|
85
|
-
if (!redirectUri
|
|
86
|
-
const msg = `--redirect-uri precisa ser https:// (Universal Link/App Link)
|
|
108
|
+
if (!isAcceptableMobileRedirectUri(redirectUri)) {
|
|
109
|
+
const msg = `--redirect-uri precisa ser https:// (Universal Link/App Link) ou http://localhost ` +
|
|
110
|
+
`(ou http://127.0.0.1) para dev — mesma regra do Core. ` +
|
|
87
111
|
`Custom scheme (ex: meuapp://) NÃO é aceito — decisão de segurança do owner (RFC 8252), ` +
|
|
88
112
|
`não é limitação temporária. Recebido: "${redirectUri}"`;
|
|
89
113
|
if (opts.json) {
|
|
@@ -269,7 +293,7 @@ export async function runMobileList(opts = {}) {
|
|
|
269
293
|
return;
|
|
270
294
|
}
|
|
271
295
|
renderTable([
|
|
272
|
-
{ header: 'ID', value: (r) => r.id,
|
|
296
|
+
{ header: 'ID', value: (r) => r.id, identificador: true },
|
|
273
297
|
{ header: 'Platform', value: (r) => r.platform, maxWidth: 10 },
|
|
274
298
|
{
|
|
275
299
|
header: 'Bundle/Package',
|
|
@@ -277,7 +301,7 @@ export async function runMobileList(opts = {}) {
|
|
|
277
301
|
maxWidth: 30,
|
|
278
302
|
},
|
|
279
303
|
{ header: 'Status', value: (r) => mobileStatusColor(r.status), maxWidth: 14 },
|
|
280
|
-
{ header: 'OIDC Client ID', value: (r) => r.oidcClientId,
|
|
304
|
+
{ header: 'OIDC Client ID', value: (r) => r.oidcClientId, identificador: true },
|
|
281
305
|
], resp.apps);
|
|
282
306
|
}
|
|
283
307
|
/**
|
package/dist/commands/new.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export interface NewMacroOptions {
|
|
2
2
|
productSlug?: string;
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* bug_7dcb68e2666a43f69ef362d2cbff94ed: era `'dev' | 'staging' | 'prod'`.
|
|
5
|
+
* `'dev'` não existe no enum do Core — ver `../lib/envs.ts`.
|
|
6
|
+
*/
|
|
7
|
+
env?: string;
|
|
4
8
|
tier?: 'dev' | 'standard' | 'enterprise';
|
|
5
9
|
customer?: string;
|
|
6
10
|
/** Pula scaffold local (útil quando o repo já existe). */
|
|
@@ -24,6 +28,32 @@ export interface NewMacroOptions {
|
|
|
24
28
|
* rodar `neetru db init` manualmente depois.
|
|
25
29
|
*/
|
|
26
30
|
skipDbInit?: boolean;
|
|
31
|
+
/** Não cria o `docs/` do produto no scaffold (repassado ao `runInit`). */
|
|
32
|
+
semDocs?: boolean;
|
|
27
33
|
json?: boolean;
|
|
28
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Decisão PURA de qual `customerId` a macro deve usar.
|
|
37
|
+
*
|
|
38
|
+
* bug_7dcb68e2666a43f69ef362d2cbff94ed — antes a macro assumia `'self'` em
|
|
39
|
+
* silêncio. `'self'` é um sentinel que o Core só aceita para produto
|
|
40
|
+
* **Neetru-owned** (`resolveDefaultCustomer`); para qualquer outro produto ele
|
|
41
|
+
* recusa a criação do workspace. Como a macro cria o produto no passo [1/5] e
|
|
42
|
+
* o workspace no [2/5], o resultado era um produto órfão no Core e um erro
|
|
43
|
+
* incompreensível no meio da macro.
|
|
44
|
+
*
|
|
45
|
+
* Agora a macro exige `--customer` explícito quando o produto não é
|
|
46
|
+
* Neetru-owned — e diz isso, em vez de deixar o Core recusar depois.
|
|
47
|
+
*/
|
|
48
|
+
export declare function decidirCustomerDaMacro(entrada: {
|
|
49
|
+
fromFlag?: string;
|
|
50
|
+
produtoEhNeetru: boolean;
|
|
51
|
+
slug: string;
|
|
52
|
+
}): {
|
|
53
|
+
ok: true;
|
|
54
|
+
customerId: string;
|
|
55
|
+
} | {
|
|
56
|
+
ok: false;
|
|
57
|
+
mensagem: string;
|
|
58
|
+
};
|
|
29
59
|
export declare function runNewMacro(name: string, opts?: NewMacroOptions): Promise<void>;
|