@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/tenants.js
CHANGED
|
@@ -14,6 +14,7 @@ import { requireToken, handleApiError } from '../lib/cli-read.js';
|
|
|
14
14
|
import { confirmDestructive, printWriteResult, } from '../lib/cli-write.js';
|
|
15
15
|
import { renderTable, fmtTimestamp } from '../lib/render.js';
|
|
16
16
|
import { pickProductId, pickTenant, promptChoice, promptText, resolveCustomer } from '../lib/pickers.js';
|
|
17
|
+
import { DEFAULT_TENANT_ENVIRONMENT_ID, ESCOLHAS_AMBIENTE_TENANT, resolverAmbienteTenant, } from '../lib/envs.js';
|
|
17
18
|
import { log } from '../utils/logger.js';
|
|
18
19
|
function colorStatus(s) {
|
|
19
20
|
if (!s)
|
|
@@ -52,11 +53,11 @@ export async function runTenantsList(opts) {
|
|
|
52
53
|
}
|
|
53
54
|
log.heading(`Tenants (${res.count})`);
|
|
54
55
|
renderTable([
|
|
55
|
-
{ header: 'ID', value: (r) => r.id,
|
|
56
|
+
{ header: 'ID', value: (r) => r.id, identificador: true },
|
|
56
57
|
{ header: 'NOME', value: (r) => r.name ?? '—', maxWidth: 28 },
|
|
57
58
|
{ header: 'STATUS', value: (r) => colorStatus(r.status) },
|
|
58
|
-
{ header: 'PRODUTO', value: (r) => r.productId ?? '—',
|
|
59
|
-
{ header: 'ENV', value: (r) => r.environmentId ?? '—' },
|
|
59
|
+
{ header: 'PRODUTO', value: (r) => r.productId ?? '—', identificador: true },
|
|
60
|
+
{ header: 'ENV', value: (r) => r.environmentId ?? '—', identificador: true },
|
|
60
61
|
{ header: 'DOMÍNIO', value: (r) => r.primaryDomain ?? '—', maxWidth: 30 },
|
|
61
62
|
], res.tenants);
|
|
62
63
|
console.log();
|
|
@@ -65,6 +66,7 @@ export async function runTenantsGet(id, opts) {
|
|
|
65
66
|
const token = await requireToken(opts.json);
|
|
66
67
|
const tenantId = await pickTenant(token, {
|
|
67
68
|
fromFlag: id,
|
|
69
|
+
inputs: ['<id>'],
|
|
68
70
|
json: opts.json,
|
|
69
71
|
message: 'Tenant:',
|
|
70
72
|
});
|
|
@@ -107,7 +109,7 @@ function warnTenantsCreateDeprecated(json) {
|
|
|
107
109
|
return; // em modo machine não printa texto fora do JSON
|
|
108
110
|
console.error(chalk.yellow('\n⚠ AVISO: `neetru tenants create` é para uso staff-only (cria tenant SEM OAuth client/secret).\n' +
|
|
109
111
|
' Para criar um ambiente completo (tenant + OAuth + secret), use:\n\n' +
|
|
110
|
-
' neetru workspaces create --product <id> --env <dev|staging|prod>\n\n' +
|
|
112
|
+
' neetru workspaces create --product <id> --env <dev-local|staging|prod>\n\n' +
|
|
111
113
|
' Se você é staff e sabe o que está fazendo, ignore este aviso.\n'));
|
|
112
114
|
}
|
|
113
115
|
export async function runTenantsCreate(opts) {
|
|
@@ -128,12 +130,16 @@ export async function runTenantsCreate(opts) {
|
|
|
128
130
|
productId: product,
|
|
129
131
|
token,
|
|
130
132
|
});
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
133
|
+
// bug_7dcb68e2666a43f69ef362d2cbff94ed: 'dev' nao existe no enum do Core
|
|
134
|
+
// (['dev-local','staging','prod']) e as rotas de tenant comparam por
|
|
135
|
+
// igualdade ESTRITA -> 400 validation_failed. O alfabeto agora vem de
|
|
136
|
+
// ../lib/envs.js, que tambem traduz o apelido historico 'dev' -> 'dev-local'.
|
|
137
|
+
const env = opts.env
|
|
138
|
+
? resolverAmbienteTenant(opts.env, opts.json)
|
|
139
|
+
: (await promptChoice('Ambiente:', [...ESCOLHAS_AMBIENTE_TENANT], {
|
|
140
|
+
default: DEFAULT_TENANT_ENVIRONMENT_ID,
|
|
141
|
+
json: opts.json,
|
|
142
|
+
}));
|
|
137
143
|
const spinner = opts.json ? null : ora({ text: 'Criando tenant…', color: 'blue' }).start();
|
|
138
144
|
let res;
|
|
139
145
|
try {
|
|
@@ -161,6 +167,7 @@ export async function runTenantsUpdate(id, opts) {
|
|
|
161
167
|
const token = await requireToken(opts.json);
|
|
162
168
|
const tenantId = await pickTenant(token, {
|
|
163
169
|
fromFlag: id,
|
|
170
|
+
inputs: ['<id>'],
|
|
164
171
|
json: opts.json,
|
|
165
172
|
message: 'Tenant a atualizar:',
|
|
166
173
|
});
|
|
@@ -172,12 +179,16 @@ export async function runTenantsUpdate(id, opts) {
|
|
|
172
179
|
json: opts.json,
|
|
173
180
|
message: 'Produto do tenant:',
|
|
174
181
|
});
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
182
|
+
// bug_7dcb68e2666a43f69ef362d2cbff94ed: 'dev' nao existe no enum do Core
|
|
183
|
+
// (['dev-local','staging','prod']) e as rotas de tenant comparam por
|
|
184
|
+
// igualdade ESTRITA -> 400 validation_failed. O alfabeto agora vem de
|
|
185
|
+
// ../lib/envs.js, que tambem traduz o apelido historico 'dev' -> 'dev-local'.
|
|
186
|
+
const env = opts.env
|
|
187
|
+
? resolverAmbienteTenant(opts.env, opts.json)
|
|
188
|
+
: (await promptChoice('Ambiente:', [...ESCOLHAS_AMBIENTE_TENANT], {
|
|
189
|
+
default: DEFAULT_TENANT_ENVIRONMENT_ID,
|
|
190
|
+
json: opts.json,
|
|
191
|
+
}));
|
|
181
192
|
const spinner = opts.json ? null : ora({ text: `Atualizando tenant ${tenantId}...`, color: 'blue' }).start();
|
|
182
193
|
try {
|
|
183
194
|
await apiRequest(`/api/cli/v1/tenants/${encodeURIComponent(tenantId)}`, {
|
|
@@ -204,6 +215,7 @@ async function runTenantsStatusChange(id, action, opts) {
|
|
|
204
215
|
const token = await requireToken(opts.json);
|
|
205
216
|
const tenantId = await pickTenant(token, {
|
|
206
217
|
fromFlag: id,
|
|
218
|
+
inputs: ['<id>'],
|
|
207
219
|
json: opts.json,
|
|
208
220
|
message: action === 'suspend' ? 'Tenant a suspender:' : 'Tenant a reativar:',
|
|
209
221
|
});
|
|
@@ -8,5 +8,14 @@ export interface UpgradeReport {
|
|
|
8
8
|
upgradeAvailable: boolean;
|
|
9
9
|
message: string;
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Compara duas versões semver: >0 se `a` for maior, <0 se menor, 0 se iguais.
|
|
13
|
+
*
|
|
14
|
+
* Sem dependência de propósito — a CLI não carrega `semver` e este caso não
|
|
15
|
+
* justifica puxar um pacote. Pré-lançamento (`1.2.3-rc.1`) é tratado como
|
|
16
|
+
* MENOR que o lançamento (`1.2.3`), que é a regra do semver e é a que importa
|
|
17
|
+
* aqui: um rc nunca deve pedir upgrade sobre o estável de mesmo número.
|
|
18
|
+
*/
|
|
19
|
+
export declare function compareSemver(a: string, b: string): number;
|
|
11
20
|
export declare function fetchLatest(fetchImpl?: typeof fetch): Promise<string | null>;
|
|
12
21
|
export declare function runUpgrade(opts?: UpgradeOptions): Promise<void>;
|
package/dist/commands/upgrade.js
CHANGED
|
@@ -14,6 +14,34 @@
|
|
|
14
14
|
import chalk from 'chalk';
|
|
15
15
|
import { CLI_VERSION } from '../version.js';
|
|
16
16
|
const NPM_REGISTRY = 'https://registry.npmjs.org/@neetru/cli';
|
|
17
|
+
/**
|
|
18
|
+
* Compara duas versões semver: >0 se `a` for maior, <0 se menor, 0 se iguais.
|
|
19
|
+
*
|
|
20
|
+
* Sem dependência de propósito — a CLI não carrega `semver` e este caso não
|
|
21
|
+
* justifica puxar um pacote. Pré-lançamento (`1.2.3-rc.1`) é tratado como
|
|
22
|
+
* MENOR que o lançamento (`1.2.3`), que é a regra do semver e é a que importa
|
|
23
|
+
* aqui: um rc nunca deve pedir upgrade sobre o estável de mesmo número.
|
|
24
|
+
*/
|
|
25
|
+
export function compareSemver(a, b) {
|
|
26
|
+
const parse = (v) => {
|
|
27
|
+
const [nucleo = '', pre = ''] = v.replace(/^v/, '').split('-', 2);
|
|
28
|
+
const nums = nucleo.split('.').map((n) => Number.parseInt(n, 10) || 0);
|
|
29
|
+
return { nums: [nums[0] ?? 0, nums[1] ?? 0, nums[2] ?? 0], pre };
|
|
30
|
+
};
|
|
31
|
+
const pa = parse(a);
|
|
32
|
+
const pb = parse(b);
|
|
33
|
+
for (let i = 0; i < 3; i++) {
|
|
34
|
+
if (pa.nums[i] !== pb.nums[i])
|
|
35
|
+
return pa.nums[i] - pb.nums[i];
|
|
36
|
+
}
|
|
37
|
+
if (pa.pre === pb.pre)
|
|
38
|
+
return 0;
|
|
39
|
+
if (pa.pre === '')
|
|
40
|
+
return 1; // lançamento > pré-lançamento
|
|
41
|
+
if (pb.pre === '')
|
|
42
|
+
return -1;
|
|
43
|
+
return pa.pre < pb.pre ? -1 : 1;
|
|
44
|
+
}
|
|
17
45
|
export async function fetchLatest(fetchImpl = fetch) {
|
|
18
46
|
const ctrl = new AbortController();
|
|
19
47
|
const timer = setTimeout(() => ctrl.abort(), 5000);
|
|
@@ -37,7 +65,22 @@ export async function runUpgrade(opts = {}) {
|
|
|
37
65
|
catch {
|
|
38
66
|
networkError = true;
|
|
39
67
|
}
|
|
40
|
-
|
|
68
|
+
// 2026-10-12: era `latest !== CLI_VERSION`, e isso mandava quem estava
|
|
69
|
+
// ADIANTE voltar atrás.
|
|
70
|
+
//
|
|
71
|
+
// Caso real e vivo: a 2.31.0 está publicada no npm desde 2026-10-09, mas o
|
|
72
|
+
// dist-tag `latest` aponta para a 2.29.0 (trava deliberada do dono — a
|
|
73
|
+
// varredura de segredo da 2.30.0 é fail-closed e pararia o deploy de quem
|
|
74
|
+
// ainda carrega chave no bundle do navegador). Quem instalou a 2.31.0 lia
|
|
75
|
+
// "Versão 2.29.0 disponível. Atualize com: npm install -g @neetru/cli@latest"
|
|
76
|
+
// e, obedecendo, fazia DOWNGRADE — perdendo os consertos que tinha.
|
|
77
|
+
//
|
|
78
|
+
// A comparação agora é por precedência semver: só sugere quando `latest` é
|
|
79
|
+
// de fato MAIOR. Quando é menor, a mensagem diz a verdade (você está à
|
|
80
|
+
// frente) em vez de mandar voltar.
|
|
81
|
+
const comparado = latest !== null ? compareSemver(latest, CLI_VERSION) : 0;
|
|
82
|
+
const upgradeAvailable = latest !== null && comparado > 0;
|
|
83
|
+
const estaAdiante = latest !== null && comparado < 0;
|
|
41
84
|
let message;
|
|
42
85
|
if (networkError || latest === null) {
|
|
43
86
|
message = 'Não foi possível verificar latest (offline?). Tente mais tarde.';
|
|
@@ -45,6 +88,12 @@ export async function runUpgrade(opts = {}) {
|
|
|
45
88
|
else if (upgradeAvailable) {
|
|
46
89
|
message = `Versão ${latest} disponível. Atualize com: npm install -g @neetru/cli@latest`;
|
|
47
90
|
}
|
|
91
|
+
else if (estaAdiante) {
|
|
92
|
+
// Não mandar voltar: quem está à frente perderia conserto ao "atualizar".
|
|
93
|
+
message =
|
|
94
|
+
`Você está na ${CLI_VERSION}, à frente da tag latest (${latest}). ` +
|
|
95
|
+
'Nada a fazer — instalar a latest seria um downgrade.';
|
|
96
|
+
}
|
|
48
97
|
else {
|
|
49
98
|
message = `Você já está na latest (${CLI_VERSION}).`;
|
|
50
99
|
}
|
|
@@ -123,6 +123,7 @@ export async function runVmMemoryStatus(serverIdArg, opts) {
|
|
|
123
123
|
const token = await requireToken(opts.json);
|
|
124
124
|
const serverId = await pickServer(token, {
|
|
125
125
|
fromFlag: serverIdArg ?? opts.server,
|
|
126
|
+
inputs: ['<serverId>', '--server'],
|
|
126
127
|
json: opts.json,
|
|
127
128
|
message: 'VM alvo:',
|
|
128
129
|
capacity: true,
|
|
@@ -17,6 +17,8 @@ export interface WebhooksUnregisterOptions {
|
|
|
17
17
|
yes?: boolean;
|
|
18
18
|
force?: boolean;
|
|
19
19
|
json?: boolean;
|
|
20
|
+
/** `--mfa-token <código>` — TOTP do step-up MFA (dispensado com sessão de 1h). */
|
|
21
|
+
mfaToken?: string;
|
|
20
22
|
}
|
|
21
23
|
export declare function runWebhooksUnregister(opts: WebhooksUnregisterOptions): Promise<void>;
|
|
22
24
|
export interface WebhooksTestOptions {
|
|
@@ -2,7 +2,7 @@ import chalk from 'chalk';
|
|
|
2
2
|
import ora from 'ora';
|
|
3
3
|
import { apiRequest } from '../lib/api-client.js';
|
|
4
4
|
import { requireToken, handleApiError } from '../lib/cli-read.js';
|
|
5
|
-
import { confirmDestructive } from '../lib/cli-write.js';
|
|
5
|
+
import { confirmDestructive, resolveStepUp } from '../lib/cli-write.js';
|
|
6
6
|
import { renderTable } from '../lib/render.js';
|
|
7
7
|
import { log } from '../utils/logger.js';
|
|
8
8
|
const ALL_EVENTS = [
|
|
@@ -69,7 +69,7 @@ export async function runWebhooksList(opts) {
|
|
|
69
69
|
}
|
|
70
70
|
log.heading(`Webhooks — ${res.productId} (${res.count})`);
|
|
71
71
|
renderTable([
|
|
72
|
-
{ header: 'ID', value: (e) => e.id,
|
|
72
|
+
{ header: 'ID', value: (e) => e.id, identificador: true },
|
|
73
73
|
{ header: 'URL', value: (e) => e.url, maxWidth: 48 },
|
|
74
74
|
{ header: 'EVENTOS', value: (e) => e.events.join(', '), maxWidth: 36 },
|
|
75
75
|
{ header: 'SECRET', value: (e) => (e.hasSecret ? chalk.green('sim') : chalk.yellow('não')) },
|
|
@@ -85,10 +85,16 @@ export async function runWebhooksUnregister(opts) {
|
|
|
85
85
|
// Gate igual ao resto das destrutivas: confirmDestructive (y/N, bypass
|
|
86
86
|
// --yes/--force, fail-closed em --json/não-TTY exigindo --yes).
|
|
87
87
|
await confirmDestructive(`Remover o webhook ${opts.id} do produto ${opts.productId}? Apaga a config e o histórico de entregas (irreversível).`, { yes: opts.yes, force: opts.force, json: opts.json });
|
|
88
|
+
// A7 (2026-10-13): o Core exige step-up MFA neste DELETE desde 2026-08-20
|
|
89
|
+
// (`requireCliStepUpMfa` em `webhooks/[id]/route.ts`, commit 7d37208d). O
|
|
90
|
+
// comando nunca mandou o cabeçalho — 401 `mfa_required` sempre, com ou sem
|
|
91
|
+
// `neetru auth mfa-session`. Mesmo caminho dos outros destrutivos: `--mfa-token`
|
|
92
|
+
// → sessão de 1h → prompt TOTP (fail-closed em --json/não-TTY).
|
|
93
|
+
const { headers } = await resolveStepUp({ mfaToken: opts.mfaToken, json: opts.json });
|
|
88
94
|
const spinner = opts.json ? null : ora({ text: 'Removendo webhook…', color: 'yellow' }).start();
|
|
89
95
|
let res;
|
|
90
96
|
try {
|
|
91
|
-
res = await apiRequest(`/api/cli/v1/webhooks/${encodeURIComponent(opts.id)}?productId=${encodeURIComponent(opts.productId)}`, { method: 'DELETE', token });
|
|
97
|
+
res = await apiRequest(`/api/cli/v1/webhooks/${encodeURIComponent(opts.id)}?productId=${encodeURIComponent(opts.productId)}`, { method: 'DELETE', token, headers });
|
|
92
98
|
spinner?.stop();
|
|
93
99
|
}
|
|
94
100
|
catch (error) {
|
|
@@ -2,12 +2,22 @@
|
|
|
2
2
|
* `neetru workspaces create|advance|list|get|open` — control plane de
|
|
3
3
|
* workspaces (runtime shared `neetru-workspaces`).
|
|
4
4
|
*
|
|
5
|
-
* Endpoints:
|
|
5
|
+
* Endpoints (conferidos contra o Core em 2026-10-12):
|
|
6
6
|
* POST /api/cli/v1/workspaces (create)
|
|
7
7
|
* POST /api/cli/v1/workspaces/{id}/advance (advance — promove bundle)
|
|
8
|
-
* GET /api/cli/v1/
|
|
9
|
-
*
|
|
8
|
+
* GET /api/cli/v1/tenants (list — filtros product/status;
|
|
9
|
+
* env filtrado aqui, normalizado)
|
|
10
|
+
* GET /api/cli/v1/tenants/{id} (get)
|
|
10
11
|
* (open) NÃO chama API — só monta a URL do painel e abre o browser.
|
|
12
|
+
*
|
|
13
|
+
* Este cabeçalho documentava `GET /workspaces` e `GET /workspaces/{id}`, e o
|
|
14
|
+
* código chamava `/tenants`. Conferido: `GET /workspaces/{id}` NÃO EXISTE no
|
|
15
|
+
* Core (só `advance` e `retry`). E `GET /workspaces` exige papel
|
|
16
|
+
* admin/operator/viewer, esconde os arquivados e devolve a lista em `items` —
|
|
17
|
+
* trocar a rota aqui deixaria a lista vazia e daria 403 a credencial
|
|
18
|
+
* `billing`, que hoje lista. Por isso a leitura FICA em `/tenants`; as colunas
|
|
19
|
+
* TIER e PRODUTO (slug), que nunca preenchiam, passam a vir do próprio
|
|
20
|
+
* `/tenants` no Core (mudança aditiva lá, sem quebrar ninguém aqui).
|
|
11
21
|
*/
|
|
12
22
|
import * as fs from 'node:fs/promises';
|
|
13
23
|
import * as path from 'node:path';
|
|
@@ -19,6 +29,8 @@ import { config } from '../lib/config.js';
|
|
|
19
29
|
import { requireToken, handleApiError, printWriteResult } from '../lib/cli-write.js';
|
|
20
30
|
import { renderTable, fmtTimestamp } from '../lib/render.js';
|
|
21
31
|
import { pickProductId, pickProductSlug, pickWorkspace, resolveProductIdentifier, isInteractive, promptChoice, promptText, resolveCustomer, } from '../lib/pickers.js';
|
|
32
|
+
import { DEFAULT_TENANT_ENVIRONMENT_ID, ESCOLHAS_AMBIENTE_TENANT, resolverAmbienteTenant, erroAmbienteTenantInvalido, normalizarAmbienteTenant, } from '../lib/envs.js';
|
|
33
|
+
import { exitWithCliError } from '../lib/cli-error.js';
|
|
22
34
|
import { log } from '../utils/logger.js';
|
|
23
35
|
import { safeExit } from '../utils/safe-exit.js';
|
|
24
36
|
/** Formata o erro 400 "Nenhum customer ativo" de forma acionável. */
|
|
@@ -53,12 +65,18 @@ export async function runWorkspacesCreate(opts) {
|
|
|
53
65
|
productId: product,
|
|
54
66
|
token,
|
|
55
67
|
});
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
68
|
+
// bug_7dcb68e2666a43f69ef362d2cbff94ed: o prompt oferecia 'dev' e usava 'dev'
|
|
69
|
+
// como padrão, mas POST /api/cli/v1/workspaces compara por igualdade ESTRITA
|
|
70
|
+
// contra ['dev-local','staging','prod'] e devolve 400 validation_failed —
|
|
71
|
+
// ou seja, aceitar o default sugerido pela própria ferramenta não criava
|
|
72
|
+
// workspace nenhum. O alfabeto agora vem de ../lib/envs.js e um `--env dev`
|
|
73
|
+
// digitado à mão é traduzido para o token canônico em vez de ir cru.
|
|
74
|
+
const env = opts.env
|
|
75
|
+
? resolverAmbienteTenant(opts.env, opts.json)
|
|
76
|
+
: (await promptChoice('Ambiente:', [...ESCOLHAS_AMBIENTE_TENANT], {
|
|
77
|
+
default: DEFAULT_TENANT_ENVIRONMENT_ID,
|
|
78
|
+
json: opts.json,
|
|
79
|
+
}));
|
|
62
80
|
// Bug #40: detecta tenant ativo existente para produto+env antes de criar.
|
|
63
81
|
if (!opts.forceDuplicate) {
|
|
64
82
|
const dupSpinner = opts.json
|
|
@@ -270,7 +288,20 @@ export async function runWorkspacesList(opts) {
|
|
|
270
288
|
res = await apiRequest(`/api/cli/v1/tenants${qs ? `?${qs}` : ''}`, { token });
|
|
271
289
|
rows = res.workspaces ?? res.tenants ?? [];
|
|
272
290
|
if (opts.env) {
|
|
273
|
-
|
|
291
|
+
// 5a copia do defeito do `--env` (2026-10-12). O conserto anterior
|
|
292
|
+
// centralizou o alfabeto e corrigiu os quatro comandos de ESCRITA — este
|
|
293
|
+
// filtro de LEITURA ficou comparando cru. Resultado: `--env dev` devolvia
|
|
294
|
+
// ZERO linhas em silencio, porque o Core grava `dev-local` e `dev` nunca
|
|
295
|
+
// casa. Zero resultado e indistinguivel de "nao existe nenhum".
|
|
296
|
+
const alvo = normalizarAmbienteTenant(opts.env);
|
|
297
|
+
if (alvo === null) {
|
|
298
|
+
spinner?.stop();
|
|
299
|
+
// bug_89d2497e: mesmo erro tipado dos comandos de escrita — com
|
|
300
|
+
// `--json`, sai o JSON com os valores válidos em vez de só stderr.
|
|
301
|
+
exitWithCliError(erroAmbienteTenantInvalido(opts.env), opts.json);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
rows = rows.filter((r) => (r.env ?? r.environmentId) === alvo);
|
|
274
305
|
}
|
|
275
306
|
spinner?.stop();
|
|
276
307
|
}
|
|
@@ -284,7 +315,7 @@ export async function runWorkspacesList(opts) {
|
|
|
284
315
|
}
|
|
285
316
|
log.heading(`Workspaces (${rows.length})`);
|
|
286
317
|
renderTable([
|
|
287
|
-
{ header: 'ID', value: (r) => r.id ?? r.workspaceId ?? '—',
|
|
318
|
+
{ header: 'ID', value: (r) => r.id ?? r.workspaceId ?? '—', identificador: true },
|
|
288
319
|
{ header: 'PRODUTO', value: (r) => r.productSlug ?? r.productId ?? '—', maxWidth: 22 },
|
|
289
320
|
{ header: 'ENV', value: (r) => r.env ?? r.environmentId ?? '—', maxWidth: 10 },
|
|
290
321
|
{ header: 'TIER', value: (r) => r.tier ?? r.resourceTier ?? '—', maxWidth: 12 },
|