@neetru/cli 2.31.0 → 2.32.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +99 -2
- package/README.md +2 -0
- 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 +118 -6
- 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 +20 -33
- package/dist/commands/deploy.d.ts +91 -2
- package/dist/commands/deploy.js +423 -78
- package/dist/commands/deployments.js +11 -6
- package/dist/commands/dev-context.js +15 -5
- package/dist/commands/docs-produto.d.ts +25 -0
- package/dist/commands/docs-produto.js +70 -8
- 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.js +8 -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 +29 -1
- package/dist/commands/new.js +92 -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 +86 -18
- 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 +8 -5
- 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 +70 -14
- package/dist/lib/api-client.d.ts +14 -0
- package/dist/lib/api-client.js +59 -6
- 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/config-schema.d.ts +8 -8
- 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/inquirer-sob-demanda.d.ts +14 -0
- package/dist/lib/inquirer-sob-demanda.js +18 -0
- package/dist/lib/mobile-local/mobile-json.js +10 -4
- package/dist/lib/pickers.d.ts +44 -7
- package/dist/lib/pickers.js +65 -7
- package/dist/lib/product-docs/sync.d.ts +6 -0
- package/dist/lib/product-docs/sync.js +10 -1
- package/dist/lib/public-secret-scan.d.ts +44 -3
- package/dist/lib/public-secret-scan.js +361 -36
- 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-produto.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/product-docs/check.js.map +0 -1
- package/dist/lib/product-docs/config.js.map +0 -1
- package/dist/lib/product-docs/dates.js.map +0 -1
- package/dist/lib/product-docs/frontmatter.js.map +0 -1
- package/dist/lib/product-docs/git.js.map +0 -1
- package/dist/lib/product-docs/markdown.js.map +0 -1
- package/dist/lib/product-docs/ops.js.map +0 -1
- package/dist/lib/product-docs/structure.js.map +0 -1
- package/dist/lib/product-docs/sync.js.map +0 -1
- package/dist/lib/product-docs/taxonomy.js.map +0 -1
- package/dist/lib/product-docs/templates.js.map +0 -1
- package/dist/lib/public-secret-scan.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
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Erro tipado da CLI (bug_89d2497e, etapa 3).
|
|
3
|
+
*
|
|
4
|
+
* Antes cada comando decidia sozinho como morrer: montava a mensagem à mão,
|
|
5
|
+
* escolhia um `safeExit(n)` e, em `--json`, um formato de payload. O modelo é o
|
|
6
|
+
* `FirebaseError` do firebase-tools (`lib/error.js`): o erro carrega o código
|
|
7
|
+
* de saída, a causa original e os filhos agregados — e quem imprime/encerra é
|
|
8
|
+
* um ponto só (`exitWithCliError`, em `src/lib/cli-error.ts`).
|
|
9
|
+
*
|
|
10
|
+
* Função pura: nada aqui imprime nem encerra o processo. O cli-kit continua sem
|
|
11
|
+
* dependência de logger/process — quem decide a saída é o call site.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Convenção ÚNICA de códigos de saída (a mesma do `handleApiError` desde a
|
|
15
|
+
* auditoria de 2026-06-20 — ver `src/lib/api-error.ts`):
|
|
16
|
+
* 1 — erro do cliente (entrada/recurso: 400, 404, 409, 422, validação)
|
|
17
|
+
* 2 — não autenticado (401)
|
|
18
|
+
* 3 — sem permissão (403)
|
|
19
|
+
* 4 — erro do servidor (5xx), rede ou desconhecido
|
|
20
|
+
*/
|
|
21
|
+
export const EXIT_CODES = {
|
|
22
|
+
client: 1,
|
|
23
|
+
unauthenticated: 2,
|
|
24
|
+
forbidden: 3,
|
|
25
|
+
server: 4,
|
|
26
|
+
};
|
|
27
|
+
export class NeetruCliError extends Error {
|
|
28
|
+
code;
|
|
29
|
+
exit;
|
|
30
|
+
children;
|
|
31
|
+
succeeded;
|
|
32
|
+
details;
|
|
33
|
+
human;
|
|
34
|
+
constructor(message, opts = {}) {
|
|
35
|
+
super(message, opts.cause !== undefined ? { cause: opts.cause } : undefined);
|
|
36
|
+
this.name = 'NeetruCliError';
|
|
37
|
+
this.code = opts.code ?? 'cli_error';
|
|
38
|
+
this.children = [...(opts.children ?? [])];
|
|
39
|
+
this.succeeded = Math.max(0, opts.succeeded ?? 0);
|
|
40
|
+
this.details = { ...(opts.details ?? {}) };
|
|
41
|
+
this.human = opts.human ?? message;
|
|
42
|
+
this.exit =
|
|
43
|
+
opts.exit ??
|
|
44
|
+
(this.children.length > 0
|
|
45
|
+
? Math.max(...this.children.map((c) => c.exit))
|
|
46
|
+
: EXIT_CODES.client);
|
|
47
|
+
}
|
|
48
|
+
/** Falha parcial: parte do lote falhou e parte deu certo. */
|
|
49
|
+
get partial() {
|
|
50
|
+
return this.children.length > 0 && this.succeeded > 0;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Payload `--json`. Sem filhos, é exatamente `{ ok:false, error, ...details,
|
|
54
|
+
* message }` — o formato que os comandos já emitiam. Com filhos, acrescenta
|
|
55
|
+
* `partial`, `succeeded`, `failed` e `children`.
|
|
56
|
+
*/
|
|
57
|
+
toJSON() {
|
|
58
|
+
return { ok: false, ...this.corpoJson() };
|
|
59
|
+
}
|
|
60
|
+
corpoJson() {
|
|
61
|
+
const base = {
|
|
62
|
+
error: this.code,
|
|
63
|
+
...this.details,
|
|
64
|
+
message: this.message,
|
|
65
|
+
};
|
|
66
|
+
if (this.children.length === 0)
|
|
67
|
+
return base;
|
|
68
|
+
return {
|
|
69
|
+
...base,
|
|
70
|
+
partial: this.partial,
|
|
71
|
+
succeeded: this.succeeded,
|
|
72
|
+
failed: this.children.length,
|
|
73
|
+
children: this.children.map((c) => c.corpoJson()),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export function isNeetruCliError(x) {
|
|
78
|
+
return x instanceof NeetruCliError;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Texto humano completo do erro, com os filhos indentados. Uma falha parcial
|
|
82
|
+
* diz que é parcial e quanto deu certo.
|
|
83
|
+
*/
|
|
84
|
+
export function renderCliError(error) {
|
|
85
|
+
if (error.children.length === 0)
|
|
86
|
+
return error.human;
|
|
87
|
+
const falhas = error.children.length;
|
|
88
|
+
const resumo = error.partial
|
|
89
|
+
? `Falha parcial: ${falhas} de ${falhas + error.succeeded} itens falharam (${error.succeeded} deram certo).`
|
|
90
|
+
: `${falhas} ${falhas === 1 ? 'item falhou' : 'itens falharam'}.`;
|
|
91
|
+
const filhos = error.children.map((c) => ` - ${renderCliError(c).split('\n').join('\n ')}`);
|
|
92
|
+
return [error.human, ` ${resumo}`, ...filhos].join('\n');
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=errors.js.map
|
package/dist/cli-kit/index.d.ts
CHANGED
|
@@ -11,3 +11,11 @@ export type { Glyphs } from './glyphs.js';
|
|
|
11
11
|
export { ok, err, warn, dim, heading } from './palette.js';
|
|
12
12
|
export { step, errorBlock, sacredPause, } from './format.js';
|
|
13
13
|
export type { ErrorBlockOpts, SacredPauseOpts } from './format.js';
|
|
14
|
+
export { EXIT_CODES, NeetruCliError, isNeetruCliError, renderCliError } from './errors.js';
|
|
15
|
+
export type { NeetruCliErrorOptions } from './errors.js';
|
|
16
|
+
export { invalidChoiceError, formatChoices } from './choices.js';
|
|
17
|
+
export type { InvalidChoiceInput } from './choices.js';
|
|
18
|
+
export { installCommandContext, setCurrentCommand, getCurrentCommand, setRootCommand, getRootCommand, commandDeclaresFlag, commandDeclaresInput, declaredFlags, declaredInputs, commandExists, adviseFlag, adviseCommand, } from './command-context.js';
|
|
19
|
+
export type { FlagAdvice, CommandAdvice } from './command-context.js';
|
|
20
|
+
export { SYNONYMS, MIN_RATIO, MAX_SUGGESTIONS, isSubcommandVerb, wordScore, scoreCandidates, suggestCommands, suggestSubcommands, reservedVerbError, } from './suggest.js';
|
|
21
|
+
export type { ReservedVerbInput } from './suggest.js';
|
package/dist/cli-kit/index.js
CHANGED
|
@@ -9,4 +9,12 @@
|
|
|
9
9
|
export { GLYPHS } from './glyphs.js';
|
|
10
10
|
export { ok, err, warn, dim, heading } from './palette.js';
|
|
11
11
|
export { step, errorBlock, sacredPause, } from './format.js';
|
|
12
|
+
// Camada de CORREÇÃO (bug_89d2497e): erro tipado, conselho validado contra o
|
|
13
|
+
// comando em execução e valores válidos de enum vindos da fonte real.
|
|
14
|
+
export { EXIT_CODES, NeetruCliError, isNeetruCliError, renderCliError } from './errors.js';
|
|
15
|
+
export { invalidChoiceError, formatChoices } from './choices.js';
|
|
16
|
+
export { installCommandContext, setCurrentCommand, getCurrentCommand, setRootCommand, getRootCommand, commandDeclaresFlag, commandDeclaresInput, declaredFlags, declaredInputs, commandExists, adviseFlag, adviseCommand, } from './command-context.js';
|
|
17
|
+
// P105: verbo de subcomando nunca é valor livre; sugestão com piso de qualidade
|
|
18
|
+
// (SYNONYMS + MIN_RATIO, o `suggest_commands` do gcloud).
|
|
19
|
+
export { SYNONYMS, MIN_RATIO, MAX_SUGGESTIONS, isSubcommandVerb, wordScore, scoreCandidates, suggestCommands, suggestSubcommands, reservedVerbError, } from './suggest.js';
|
|
12
20
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { NeetruCliError } from './errors.js';
|
|
2
|
+
/** Verbo digitado → verbo(s) que a CLI usa. */
|
|
3
|
+
export declare const SYNONYMS: Readonly<Record<string, readonly string[]>>;
|
|
4
|
+
/** Mínimo da razão pontuação/pontuação-do-primeiro para entrar na sugestão. */
|
|
5
|
+
export declare const MIN_RATIO = 0.7;
|
|
6
|
+
/** No máximo isto de sugestões. */
|
|
7
|
+
export declare const MAX_SUGGESTIONS = 10;
|
|
8
|
+
/**
|
|
9
|
+
* A palavra é, de fato, verbo de subcomando DESTE comando? Sim quando é um dos
|
|
10
|
+
* subcomandos dados (nome ou apelido) ou um sinônimo (`SYNONYMS`) de um deles.
|
|
11
|
+
* Sem diferenciar caixa, sem espaços nas pontas.
|
|
12
|
+
*
|
|
13
|
+
* Revisão do #87 (BAIXO 6): a 1ª versão recusava uma lista GLOBAL de verbos em
|
|
14
|
+
* qualquer texto livre, e `neetru chat send show` (resposta comum em PT-BR)
|
|
15
|
+
* passou a ser recusado sem que `show` fosse subcomando de `chat`. A recusa
|
|
16
|
+
* agora depende dos subcomandos de verdade de quem pergunta: para `chat send`,
|
|
17
|
+
* só `channels`, `identity`/`apelido`, `send` e `history`; para
|
|
18
|
+
* `chat identity`, os verbos dele (`show`, `set`, `clear`…) e seus sinônimos.
|
|
19
|
+
*/
|
|
20
|
+
export declare function isSubcommandVerb(word: string, subcommands: readonly string[]): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Pontuação de uma palavra digitada contra uma palavra de um comando — o
|
|
23
|
+
* `_WordScore` do gcloud, linha a linha. Sempre ≥ 0; zero = sem relação.
|
|
24
|
+
*/
|
|
25
|
+
export declare function wordScore(index: number, word: string, canonical: string, canonicalLength: number): number;
|
|
26
|
+
/**
|
|
27
|
+
* Candidatos pontuados, do maior para o menor (empate: ordem lexicográfica).
|
|
28
|
+
* Só entra quem pontua > 0. Cada candidato é a lista de palavras do comando.
|
|
29
|
+
*/
|
|
30
|
+
export declare function scoreCandidates(words: readonly string[], candidates: ReadonlyArray<readonly string[]>): Array<{
|
|
31
|
+
command: readonly string[];
|
|
32
|
+
score: number;
|
|
33
|
+
}>;
|
|
34
|
+
/**
|
|
35
|
+
* Comandos sugeridos para as palavras digitadas — o `GetCommandSuggestions`
|
|
36
|
+
* do gcloud: só quem pontua > 0 e faz pelo menos `MIN_RATIO` da pontuação do
|
|
37
|
+
* primeiro, no máximo `MAX_SUGGESTIONS`. Vazio quando nada pontua.
|
|
38
|
+
*/
|
|
39
|
+
export declare function suggestCommands(words: readonly string[], candidates: ReadonlyArray<readonly string[]>): string[];
|
|
40
|
+
/**
|
|
41
|
+
* Sugestões para a palavra digitada, entre os subcomandos dados. Vazio quando
|
|
42
|
+
* nada passa o piso — aí quem chama lista as escolhas, nunca chuta.
|
|
43
|
+
*/
|
|
44
|
+
export declare function suggestSubcommands(word: string, subcommands: readonly string[]): string[];
|
|
45
|
+
export interface ReservedVerbInput {
|
|
46
|
+
/** O verbo recebido como valor, como a pessoa digitou. */
|
|
47
|
+
verb: string;
|
|
48
|
+
/** O comando onde ele chegou, sem o `neetru` (ex.: `'chat identity'`). */
|
|
49
|
+
command: string;
|
|
50
|
+
/**
|
|
51
|
+
* O comando cujos subcomandos são sugeridos, sem o `neetru`. Padrão:
|
|
52
|
+
* `command`. Ex.: a palavra chega em `chat send`, e os subcomandos são de `chat`.
|
|
53
|
+
*/
|
|
54
|
+
parent?: string;
|
|
55
|
+
/** O que o comando esperava naquela posição (ex.: `'um apelido'`). */
|
|
56
|
+
what: string;
|
|
57
|
+
/**
|
|
58
|
+
* Os subcomandos/verbos que o comando aceita — a MESMA lista que ele usa
|
|
59
|
+
* para decidir. Vazio = sem sugestão possível (só a recusa).
|
|
60
|
+
*/
|
|
61
|
+
subcommands: readonly string[];
|
|
62
|
+
/** Apelido → nome do subcomando (ex.: `apelido → identity`): a sugestão vai direto ao nome. */
|
|
63
|
+
aliases?: Readonly<Record<string, string>>;
|
|
64
|
+
/** Como passar a mesma palavra como texto, quando existe jeito. */
|
|
65
|
+
escapeHint?: string;
|
|
66
|
+
/** Código do JSON. Padrão: `'uso_invalido'`. */
|
|
67
|
+
code?: string;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Recusa um verbo usado como valor e sugere o subcomando certo — ou, sem
|
|
71
|
+
* sugestão que passe o piso, lista as escolhas. Exit 1 (erro do cliente). No
|
|
72
|
+
* JSON: `value`, `suggestions` (comandos completos) e `valid`.
|
|
73
|
+
*/
|
|
74
|
+
export declare function reservedVerbError(input: ReservedVerbInput): NeetruCliError;
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verbo de subcomando nunca é valor livre, e sugestão só com piso de qualidade
|
|
3
|
+
* (P105 / bug_89d2497e; o caso que nasceu daqui foi o bug_09574d4b).
|
|
4
|
+
*
|
|
5
|
+
* O bug: `neetru chat identity show` GRAVOU o apelido "show", e
|
|
6
|
+
* `identity set "X"` gravou "set". O comando recebia texto livre posicional e
|
|
7
|
+
* aceitava qualquer palavra — inclusive o verbo que a pessoa usou achando que
|
|
8
|
+
* era subcomando. O gcloud não teria aceitado essa string: ele sabe quais
|
|
9
|
+
* palavras são verbos e, quando a palavra não é escolha válida, sugere o
|
|
10
|
+
* comando certo ou lista as escolhas — nunca adivinha lixo.
|
|
11
|
+
*
|
|
12
|
+
* O MODELO é o `calliope/suggest_commands.py` do gcloud (lido no SDK instalado
|
|
13
|
+
* nesta máquina, `google-cloud-sdk/lib/googlecloudsdk/calliope`):
|
|
14
|
+
* - `SYNONYMS`: verbo digitado → verbo que a CLI de fato usa. O gcloud mapeia
|
|
15
|
+
* para os verbos DELE (`show → describe`); aqui o mapa aponta para os nossos
|
|
16
|
+
* (`describe → show`), e um verbo pode ter mais de um correspondente.
|
|
17
|
+
* - `_WordScore`: só pontua quando uma palavra CONTÉM a outra, e só em começo
|
|
18
|
+
* de palavra (ou depois de `-`). Sem relação de texto, a pontuação é zero e
|
|
19
|
+
* o candidato some. É esse o piso absoluto: nada de distância de edição, que
|
|
20
|
+
* acha "parecido" em qualquer par de palavras curtas.
|
|
21
|
+
* - `MIN_RATIO = 0.7`: entre os que pontuam, só entra quem faz pelo menos 70%
|
|
22
|
+
* da pontuação do primeiro. `MAX_SUGGESTIONS = 10`.
|
|
23
|
+
* - O histórico de uso do usuário (`_GetSurfaceHistoryFrequencies`) NÃO foi
|
|
24
|
+
* portado: a CLI não guarda histórico de comandos, e inventar um seria pior
|
|
25
|
+
* que não ranquear por ele.
|
|
26
|
+
*
|
|
27
|
+
* Quando nada passa o piso, quem chama LISTA as escolhas válidas (o gcloud faz
|
|
28
|
+
* o mesmo em erro de argumento, `parser_extensions.py`) em vez de sugerir.
|
|
29
|
+
*/
|
|
30
|
+
import { formatChoices } from './choices.js';
|
|
31
|
+
import { EXIT_CODES, NeetruCliError } from './errors.js';
|
|
32
|
+
/** Verbo digitado → verbo(s) que a CLI usa. */
|
|
33
|
+
export const SYNONYMS = {
|
|
34
|
+
describe: ['show', 'get'],
|
|
35
|
+
get: ['show', 'describe'],
|
|
36
|
+
show: ['describe', 'get'],
|
|
37
|
+
view: ['show'],
|
|
38
|
+
ver: ['show'],
|
|
39
|
+
list: ['show'],
|
|
40
|
+
update: ['set'],
|
|
41
|
+
modify: ['set', 'update'],
|
|
42
|
+
patch: ['set', 'update'],
|
|
43
|
+
change: ['set', 'update'],
|
|
44
|
+
definir: ['set'],
|
|
45
|
+
unset: ['clear'],
|
|
46
|
+
remove: ['clear', 'delete'],
|
|
47
|
+
delete: ['clear', 'remove'],
|
|
48
|
+
reset: ['clear'],
|
|
49
|
+
limpar: ['clear'],
|
|
50
|
+
};
|
|
51
|
+
/** Mínimo da razão pontuação/pontuação-do-primeiro para entrar na sugestão. */
|
|
52
|
+
export const MIN_RATIO = 0.7;
|
|
53
|
+
/** No máximo isto de sugestões. */
|
|
54
|
+
export const MAX_SUGGESTIONS = 10;
|
|
55
|
+
/**
|
|
56
|
+
* A palavra é, de fato, verbo de subcomando DESTE comando? Sim quando é um dos
|
|
57
|
+
* subcomandos dados (nome ou apelido) ou um sinônimo (`SYNONYMS`) de um deles.
|
|
58
|
+
* Sem diferenciar caixa, sem espaços nas pontas.
|
|
59
|
+
*
|
|
60
|
+
* Revisão do #87 (BAIXO 6): a 1ª versão recusava uma lista GLOBAL de verbos em
|
|
61
|
+
* qualquer texto livre, e `neetru chat send show` (resposta comum em PT-BR)
|
|
62
|
+
* passou a ser recusado sem que `show` fosse subcomando de `chat`. A recusa
|
|
63
|
+
* agora depende dos subcomandos de verdade de quem pergunta: para `chat send`,
|
|
64
|
+
* só `channels`, `identity`/`apelido`, `send` e `history`; para
|
|
65
|
+
* `chat identity`, os verbos dele (`show`, `set`, `clear`…) e seus sinônimos.
|
|
66
|
+
*/
|
|
67
|
+
export function isSubcommandVerb(word, subcommands) {
|
|
68
|
+
const w = word.trim().toLowerCase();
|
|
69
|
+
if (!w)
|
|
70
|
+
return false;
|
|
71
|
+
if (subcommands.includes(w))
|
|
72
|
+
return true;
|
|
73
|
+
return (SYNONYMS[w] ?? []).some((s) => subcommands.includes(s));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Pontuação de uma palavra digitada contra uma palavra de um comando — o
|
|
77
|
+
* `_WordScore` do gcloud, linha a linha. Sempre ≥ 0; zero = sem relação.
|
|
78
|
+
*/
|
|
79
|
+
export function wordScore(index, word, canonical, canonicalLength) {
|
|
80
|
+
if (!word || !canonical)
|
|
81
|
+
return 0;
|
|
82
|
+
let shorter;
|
|
83
|
+
let longer;
|
|
84
|
+
if (canonical.includes(word)) {
|
|
85
|
+
shorter = word;
|
|
86
|
+
longer = canonical;
|
|
87
|
+
}
|
|
88
|
+
else if (word.includes(canonical)) {
|
|
89
|
+
shorter = canonical;
|
|
90
|
+
longer = word;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
// O acerto no meio precisa cair em fronteira de palavra.
|
|
96
|
+
const hit = longer.indexOf(shorter);
|
|
97
|
+
if (hit > 0 && longer[hit - 1] !== '-')
|
|
98
|
+
return 0;
|
|
99
|
+
let score = 10;
|
|
100
|
+
if (canonicalLength === 1)
|
|
101
|
+
score += 30;
|
|
102
|
+
else if (canonicalLength === 2)
|
|
103
|
+
score += 20;
|
|
104
|
+
else if (canonicalLength === 3)
|
|
105
|
+
score += 10;
|
|
106
|
+
if (index === 0)
|
|
107
|
+
score += 25;
|
|
108
|
+
else if (index === 1)
|
|
109
|
+
score += 15;
|
|
110
|
+
else
|
|
111
|
+
score += 5;
|
|
112
|
+
let extra = longer.length - shorter.length;
|
|
113
|
+
if (extra <= 2) {
|
|
114
|
+
extra = 3 - extra;
|
|
115
|
+
if (longer.startsWith(shorter))
|
|
116
|
+
extra *= 2;
|
|
117
|
+
score += extra;
|
|
118
|
+
}
|
|
119
|
+
if (index === 0 && canonicalLength > 1)
|
|
120
|
+
score += 30;
|
|
121
|
+
else if (index > 0 && canonicalLength > index + 1)
|
|
122
|
+
score += 15;
|
|
123
|
+
return score;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Candidatos pontuados, do maior para o menor (empate: ordem lexicográfica).
|
|
127
|
+
* Só entra quem pontua > 0. Cada candidato é a lista de palavras do comando.
|
|
128
|
+
*/
|
|
129
|
+
export function scoreCandidates(words, candidates) {
|
|
130
|
+
const normalizadas = words.map((w) => w.trim().toLowerCase().replace(/_/g, '-')).filter(Boolean);
|
|
131
|
+
const out = [];
|
|
132
|
+
for (const cand of candidates) {
|
|
133
|
+
const casadas = new Set();
|
|
134
|
+
let score = 0;
|
|
135
|
+
cand.forEach((canonica, index) => {
|
|
136
|
+
for (const w of normalizadas) {
|
|
137
|
+
let inc = wordScore(index, w, canonica, cand.length);
|
|
138
|
+
for (const alt of SYNONYMS[w] ?? []) {
|
|
139
|
+
inc = Math.max(inc, wordScore(index, alt, canonica, cand.length));
|
|
140
|
+
}
|
|
141
|
+
if (inc) {
|
|
142
|
+
casadas.add(w);
|
|
143
|
+
score += inc;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
if (normalizadas.length > 0 && casadas.size === normalizadas.length)
|
|
148
|
+
score += 10;
|
|
149
|
+
if (score > 0)
|
|
150
|
+
out.push({ command: cand, score });
|
|
151
|
+
}
|
|
152
|
+
out.sort((a, b) => b.score - a.score || a.command.join(' ').localeCompare(b.command.join(' ')));
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Comandos sugeridos para as palavras digitadas — o `GetCommandSuggestions`
|
|
157
|
+
* do gcloud: só quem pontua > 0 e faz pelo menos `MIN_RATIO` da pontuação do
|
|
158
|
+
* primeiro, no máximo `MAX_SUGGESTIONS`. Vazio quando nada pontua.
|
|
159
|
+
*/
|
|
160
|
+
export function suggestCommands(words, candidates) {
|
|
161
|
+
const pontuados = scoreCandidates(words, candidates);
|
|
162
|
+
if (pontuados.length === 0)
|
|
163
|
+
return [];
|
|
164
|
+
const topo = pontuados[0].score;
|
|
165
|
+
return pontuados
|
|
166
|
+
.filter((p) => p.score / topo >= MIN_RATIO)
|
|
167
|
+
.slice(0, MAX_SUGGESTIONS)
|
|
168
|
+
.map((p) => p.command.join(' '));
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Sugestões para a palavra digitada, entre os subcomandos dados. Vazio quando
|
|
172
|
+
* nada passa o piso — aí quem chama lista as escolhas, nunca chuta.
|
|
173
|
+
*/
|
|
174
|
+
export function suggestSubcommands(word, subcommands) {
|
|
175
|
+
return suggestCommands([word], subcommands.map((s) => [s]));
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Recusa um verbo usado como valor e sugere o subcomando certo — ou, sem
|
|
179
|
+
* sugestão que passe o piso, lista as escolhas. Exit 1 (erro do cliente). No
|
|
180
|
+
* JSON: `value`, `suggestions` (comandos completos) e `valid`.
|
|
181
|
+
*/
|
|
182
|
+
export function reservedVerbError(input) {
|
|
183
|
+
const pai = input.parent ?? input.command;
|
|
184
|
+
const apelidoDe = input.aliases?.[input.verb.trim().toLowerCase()];
|
|
185
|
+
const sugestoes = (apelidoDe ? [apelidoDe] : suggestSubcommands(input.verb, input.subcommands)).map((s) => `neetru ${pai} ${s}`);
|
|
186
|
+
const linhas = [
|
|
187
|
+
`"${input.verb}" é palavra de comando da CLI e não vale como ${input.what} em \`neetru ${input.command}\`.`,
|
|
188
|
+
];
|
|
189
|
+
if (sugestoes.length > 0) {
|
|
190
|
+
linhas.push(`Você quis dizer: ${sugestoes.map((s) => `\`${s}\``).join(' ou ')}?`);
|
|
191
|
+
}
|
|
192
|
+
else if (input.subcommands.length > 0) {
|
|
193
|
+
linhas.push(`Subcomandos de \`neetru ${pai}\`: ${formatChoices(input.subcommands)}.`);
|
|
194
|
+
}
|
|
195
|
+
if (input.escapeHint)
|
|
196
|
+
linhas.push(input.escapeHint);
|
|
197
|
+
return new NeetruCliError(linhas.join('\n '), {
|
|
198
|
+
code: input.code ?? 'uso_invalido',
|
|
199
|
+
exit: EXIT_CODES.client,
|
|
200
|
+
details: {
|
|
201
|
+
value: input.verb,
|
|
202
|
+
suggestions: sugestoes,
|
|
203
|
+
valid: [...input.subcommands],
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=suggest.js.map
|
|
@@ -202,7 +202,7 @@ export async function runOidcLoginList(opts) {
|
|
|
202
202
|
}
|
|
203
203
|
log.heading(`Login-clients OIDC — produto ${opts.productId} (${res.count})`);
|
|
204
204
|
renderTable([
|
|
205
|
-
{ header: 'CLIENT ID', value: (r) => r.clientId,
|
|
205
|
+
{ header: 'CLIENT ID', value: (r) => r.clientId, identificador: true },
|
|
206
206
|
{ header: 'NOME', value: (r) => r.name, maxWidth: 24 },
|
|
207
207
|
{ header: 'REDIRECT_URI', value: (r) => (r.redirectUris ?? []).join(', '), maxWidth: 44 },
|
|
208
208
|
{
|
|
@@ -120,7 +120,7 @@ export async function runSdkCredentialList(opts) {
|
|
|
120
120
|
}
|
|
121
121
|
log.heading(`Credenciais OIDC — produto ${opts.productId} (${res.count})`);
|
|
122
122
|
renderTable([
|
|
123
|
-
{ header: 'CLIENT ID', value: (r) => r.clientId,
|
|
123
|
+
{ header: 'CLIENT ID', value: (r) => r.clientId, identificador: true },
|
|
124
124
|
{ header: 'NOME', value: (r) => r.name, maxWidth: 28 },
|
|
125
125
|
{ header: 'ESCOPOS', value: (r) => r.allowedScopes.join(', '), maxWidth: 40 },
|
|
126
126
|
{
|
|
@@ -6,7 +6,7 @@ export type Shell = 'bash' | 'zsh' | 'pwsh';
|
|
|
6
6
|
* IMPORTANTE: incluir TODOS os `program.command('X')` de `src/index.ts`.
|
|
7
7
|
* O regression test `top-level-commands-coverage.test.ts` exige >=95%.
|
|
8
8
|
*/
|
|
9
|
-
export declare const TOP_LEVEL_COMMANDS: readonly ["add", "admin", "agent", "ai", "api-catalog", "ar", "archive", "artifact-registry", "audit", "auth", "autocomplete", "billing", "bootstrap", "bug", "build", "builds", "cloud-run", "code", "config", "customers", "db", "db-hosts", "deploy", "deployments", "dev", "dns", "docs", "doctor", "dr", "env", "hosting", "init", "login", "logout", "logs", "menu", "mobile", "mocks", "new", "open", "ops", "products", "promote", "publish", "schema", "servers", "smoke", "status", "support", "tenants", "ui", "upgrade", "validate", "vm", "whoami", "workspaces"];
|
|
9
|
+
export declare const TOP_LEVEL_COMMANDS: readonly ["add", "admin", "agent", "ai", "api-catalog", "ar", "archive", "artifact-registry", "audit", "auth", "autocomplete", "billing", "bootstrap", "bug", "build", "builds", "cloud-run", "code", "config", "customers", "db", "db-hosts", "deploy", "deployments", "dev", "dns", "docs", "doctor", "dr", "env", "hosting", "init", "login", "logout", "logs", "menu", "mobile", "mocks", "new", "open", "ops", "products", "promote", "publish", "schema", "secrets", "servers", "smoke", "status", "support", "tenants", "ui", "upgrade", "validate", "vm", "whoami", "workspaces"];
|
|
10
10
|
export interface AutocompleteOptions {
|
|
11
11
|
shell?: string;
|
|
12
12
|
}
|
|
@@ -73,6 +73,7 @@ export const TOP_LEVEL_COMMANDS = [
|
|
|
73
73
|
'promote',
|
|
74
74
|
'publish',
|
|
75
75
|
'schema', // neetru schema — inspecionar spec OpenAPI do Core
|
|
76
|
+
'secrets', // neetru secrets — segredos do próprio produto (set/list/archive)
|
|
76
77
|
'servers',
|
|
77
78
|
'smoke', // neetru smoke — percorre páginas do produto local antes do deploy
|
|
78
79
|
'status',
|
package/dist/commands/bug.d.ts
CHANGED
|
@@ -1,3 +1,61 @@
|
|
|
1
|
+
interface BugRow {
|
|
2
|
+
id: string;
|
|
3
|
+
title?: string;
|
|
4
|
+
status?: string;
|
|
5
|
+
severity?: string;
|
|
6
|
+
category?: string;
|
|
7
|
+
assignedTo?: string;
|
|
8
|
+
productId?: string;
|
|
9
|
+
reportedAt?: unknown;
|
|
10
|
+
updatedAt?: unknown;
|
|
11
|
+
reportedBy?: {
|
|
12
|
+
actorType?: string;
|
|
13
|
+
actorId?: string;
|
|
14
|
+
email?: string;
|
|
15
|
+
};
|
|
16
|
+
description?: string;
|
|
17
|
+
reproductionSteps?: string;
|
|
18
|
+
expectedBehavior?: string;
|
|
19
|
+
actualBehavior?: string;
|
|
20
|
+
resolution?: {
|
|
21
|
+
summary?: string;
|
|
22
|
+
commitSha?: string;
|
|
23
|
+
resolvedBy?: string;
|
|
24
|
+
resolvedAt?: unknown;
|
|
25
|
+
};
|
|
26
|
+
comments?: Array<{
|
|
27
|
+
author: string;
|
|
28
|
+
body: string;
|
|
29
|
+
at?: unknown;
|
|
30
|
+
}>;
|
|
31
|
+
environment?: {
|
|
32
|
+
cliVersion?: string;
|
|
33
|
+
sdkVersion?: string;
|
|
34
|
+
nodeVersion?: string;
|
|
35
|
+
os?: string;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Limpa o que o usuário colou: espaços, reticências da tabela antiga, caixa
|
|
40
|
+
* alta, e aceita o hex sem o `bug_` na frente (`a4f84c1b` → `bug_a4f84c1b`).
|
|
41
|
+
*/
|
|
42
|
+
export declare function normalizarEntradaDeId(entrada: string): string;
|
|
43
|
+
export type ResolucaoDeIdDeBug = {
|
|
44
|
+
ok: true;
|
|
45
|
+
id: string;
|
|
46
|
+
} | {
|
|
47
|
+
ok: false;
|
|
48
|
+
motivo: 'curto_demais' | 'nao_encontrado' | 'ambiguo';
|
|
49
|
+
candidatos: BugRow[];
|
|
50
|
+
};
|
|
51
|
+
/** Pura: decide o id a partir da entrada e da lista. Testável sem rede. */
|
|
52
|
+
export declare function escolherBugPorPrefixo(entrada: string, rows: BugRow[]): ResolucaoDeIdDeBug;
|
|
53
|
+
/**
|
|
54
|
+
* Resolve o id que o usuário digitou pro id completo. Id completo não custa
|
|
55
|
+
* chamada extra; prefixo custa UMA listagem. Falha sai com mensagem que diz o
|
|
56
|
+
* que fazer, em vez do "não encontrado" que mentia.
|
|
57
|
+
*/
|
|
58
|
+
export declare function resolverIdDoBug(entrada: string, token: string, json?: boolean): Promise<string>;
|
|
1
59
|
export interface BugReportOptions {
|
|
2
60
|
title?: string;
|
|
3
61
|
body?: string;
|
|
@@ -85,3 +143,4 @@ export interface BugCommentOptions {
|
|
|
85
143
|
* neetru bug comment bug_abc123 --body "Testei em Node 22 — reproduzível."
|
|
86
144
|
*/
|
|
87
145
|
export declare function runBugComment(id: string, opts: BugCommentOptions): Promise<void>;
|
|
146
|
+
export {};
|