@neetru/cli 2.31.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 +91 -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 +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 +91 -2
- package/dist/commands/deploy.js +414 -69
- 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 +7 -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 +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 +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/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/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
package/dist/commands/build.d.ts
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
|
+
import { type RuntimeEnvironmentId } from '../lib/envs.js';
|
|
1
2
|
export interface BuildOptions {
|
|
2
3
|
product?: string;
|
|
4
|
+
/**
|
|
5
|
+
* bug_678ddc98: diretório do APP a construir, relativo a onde o comando foi
|
|
6
|
+
* invocado. Em monorepo (pnpm workspaces + Turborepo) o app não fica na raiz
|
|
7
|
+
* do repo — antes disso só dava pra buildar com `cd apps/web`, o que levava
|
|
8
|
+
* junto o `.neetru-build` e a resolução de lockfile pro lugar errado.
|
|
9
|
+
*
|
|
10
|
+
* O artefato continua saindo onde o comando foi invocado (a raiz do repo, em
|
|
11
|
+
* geral) pra que o `neetru deploy` seguinte, que procura
|
|
12
|
+
* `<cwd>/.neetru-build/manifest.json`, encontre o que acabou de ser gerado.
|
|
13
|
+
*/
|
|
14
|
+
app?: string;
|
|
3
15
|
/**
|
|
4
16
|
* Stack a usar no build. 'nextjs' é alias de conveniência da CLI — normalizado
|
|
5
17
|
* pra 'node' internamente (bug_ebac4e6c: antes causava "Stack desconhecida: nextjs").
|
|
@@ -34,7 +46,7 @@ export interface BuildOptions {
|
|
|
34
46
|
* spawn-env (que dotenv/Next.js NUNCA sobrescreve a partir de arquivo)
|
|
35
47
|
* — neutraliza o arquivo ambiente sem tocar em nada no disco do dev.
|
|
36
48
|
*/
|
|
37
|
-
targetEnv?:
|
|
49
|
+
targetEnv?: RuntimeEnvironmentId;
|
|
38
50
|
/**
|
|
39
51
|
* SETOR 5.1 (PLANO_MESTRE_QUALIDADE_ECOSSISTEMA_2026-08-03): saída
|
|
40
52
|
* machine-readable. Suprime banner/spinner/logs humanos do stdout, roteia a
|
|
@@ -62,6 +74,17 @@ export interface BuildManifest {
|
|
|
62
74
|
sha256: string;
|
|
63
75
|
sizeBytes: number;
|
|
64
76
|
entrypoint?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Prefixo do app dentro do standalone, quando o Next.js ANINHOU o app num
|
|
79
|
+
* monorepo (`apps/web`). `''`/ausente = app na raiz do tarball, layout que o
|
|
80
|
+
* agente sabe inferir sozinho.
|
|
81
|
+
*
|
|
82
|
+
* Existe pra o `deploy` conseguir distinguir "entrypoint que o agente NÃO tem
|
|
83
|
+
* como adivinhar" de "entrypoint que ele adivinha melhor que a gente" — ver
|
|
84
|
+
* `entrypointParaDeploy` em `deploy.ts`. Sem este campo o deploy teria que
|
|
85
|
+
* inferir o aninhamento do formato da string, inferência sobre inferência.
|
|
86
|
+
*/
|
|
87
|
+
appPrefix?: string;
|
|
65
88
|
builtAt: string;
|
|
66
89
|
}
|
|
67
90
|
/**
|
package/dist/commands/build.js
CHANGED
|
@@ -28,7 +28,14 @@ import ora from 'ora';
|
|
|
28
28
|
import { log } from '../utils/logger.js';
|
|
29
29
|
import { safeExit } from '../utils/safe-exit.js';
|
|
30
30
|
import { normalizeTarget } from './env.js';
|
|
31
|
+
import { RUNTIME_ENVIRONMENT_IDS } from '../lib/envs.js';
|
|
32
|
+
import { formatChoices } from '../cli-kit/choices.js';
|
|
31
33
|
import { registerSpinner, unregisterSpinner } from '../utils/spinner-registry.js';
|
|
34
|
+
import { CodificacaoInvalida, decodificarUtf8, semBomInicial } from '../lib/texto-utf8.js';
|
|
35
|
+
import { variaveisDoEnvFile } from '../lib/env-file-do-build.js';
|
|
36
|
+
// bug_678ddc98: detecção de alvo — diretório do app, gerenciador de pacote e
|
|
37
|
+
// layout do standalone (possivelmente aninhado). Ver `src/lib/build-targets.ts`.
|
|
38
|
+
import { detectPackageManager, comandoInstall, comandoRunScript, comandoExecBin, resolveStandaloneLayout, baseDeInjecaoNoTar, } from '../lib/build-targets.js';
|
|
32
39
|
const CONFIG_FILENAMES = ['neetru.config.json', '.neetru.json'];
|
|
33
40
|
function fileExists(p) {
|
|
34
41
|
try {
|
|
@@ -318,17 +325,43 @@ function isStandaloneBuildDir(cwd) {
|
|
|
318
325
|
* package.json
|
|
319
326
|
* node_modules/… (mínimo, tracejado pelo Next.js)
|
|
320
327
|
* .next/… (server chunks, BUILD_ID, etc.)
|
|
321
|
-
* .next/static/… (injetado de <
|
|
322
|
-
* public/… (injetado de <
|
|
328
|
+
* .next/static/… (injetado de <appDir>/.next/static)
|
|
329
|
+
* public/… (injetado de <appDir>/public)
|
|
330
|
+
*
|
|
331
|
+
* bug_678ddc98 (MONOREPO): o layout acima só vale pra repo de app ÚNICO. Num
|
|
332
|
+
* monorepo o Next.js traceja a partir do `outputFileTracingRoot` e ANINHA o app
|
|
333
|
+
* dentro do standalone, porque o `node_modules` tracejado mora na raiz e o
|
|
334
|
+
* `server.js` precisa enxergá-lo subindo a árvore:
|
|
335
|
+
*
|
|
336
|
+
* raiz-do-tar/
|
|
337
|
+
* node_modules/… (tracejado, compartilhado pelo workspace)
|
|
338
|
+
* packages/ui/… (pacotes internos que o app importa)
|
|
339
|
+
* apps/web/server.js (entrypoint REAL → `node apps/web/server.js`)
|
|
340
|
+
* apps/web/.next/…
|
|
341
|
+
* apps/web/.next/static/… (injetado — tem que ir pro prefixo, não pra raiz)
|
|
342
|
+
* apps/web/public/… (idem)
|
|
343
|
+
*
|
|
344
|
+
* Antes deste fix o `static`/`public` iam pra RAIZ do tar enquanto o server
|
|
345
|
+
* rodava de `apps/web/` — o app subia sem CSS/JS e sem os estáticos. `appPrefix`
|
|
346
|
+
* vem de `resolveStandaloneLayout` (`''` em repo de app único: layout idêntico
|
|
347
|
+
* ao de antes, byte a byte).
|
|
323
348
|
*
|
|
324
349
|
* Um único `tar` com múltiplos `-C` — não faz staging-copy (não duplica em
|
|
325
350
|
* disco). Os `--exclude` (inclui ENV_TAR_EXCLUDES) são globais, valem pros três
|
|
326
351
|
* `-C`.
|
|
327
352
|
*/
|
|
328
|
-
async function tarStandalone(
|
|
329
|
-
const standaloneDir = path.join(
|
|
330
|
-
const staticDir = path.join(
|
|
331
|
-
const publicDir = path.join(
|
|
353
|
+
async function tarStandalone(appDir, dest, exclude = [], quiet = false, appPrefix = '') {
|
|
354
|
+
const standaloneDir = path.join(appDir, '.next', 'standalone');
|
|
355
|
+
const staticDir = path.join(appDir, '.next', 'static');
|
|
356
|
+
const publicDir = path.join(appDir, 'public');
|
|
357
|
+
// bug_678ddc98: pra gravar o membro já aninhado (`apps/web/.next/static`) sem
|
|
358
|
+
// `--transform`/`-s` (não portáveis entre GNU tar e bsdtar), o `-C` recua até
|
|
359
|
+
// a raiz de tracing e o membro leva o prefixo junto. Ver `baseDeInjecaoNoTar`.
|
|
360
|
+
const injecao = baseDeInjecaoNoTar(appDir, appPrefix);
|
|
361
|
+
if (!injecao) {
|
|
362
|
+
throw new Error(`Não foi possível mapear o prefixo "${appPrefix}" do standalone pro disco a partir de ${appDir}. ` +
|
|
363
|
+
'Isso indica um layout de standalone inesperado — abortando pra não empacotar estáticos no caminho errado.');
|
|
364
|
+
}
|
|
332
365
|
const isWinGnu = process.platform === 'win32' && (await tarIsGnu());
|
|
333
366
|
const norm = (p) => (isWinGnu ? normalizePathForTar(p) : p);
|
|
334
367
|
const args = [];
|
|
@@ -340,18 +373,18 @@ async function tarStandalone(cwd, dest, exclude = [], quiet = false) {
|
|
|
340
373
|
for (const ex of [...exclude, ...ENV_TAR_EXCLUDES]) {
|
|
341
374
|
args.push(`--exclude=${ex}`);
|
|
342
375
|
}
|
|
343
|
-
// 1) Todo o conteúdo do standalone → RAIZ do tar
|
|
376
|
+
// 1) Todo o conteúdo do standalone → RAIZ do tar (com o aninhamento que o
|
|
377
|
+
// Next.js produziu, quando houver).
|
|
344
378
|
args.push('-C', norm(standaloneDir), '.');
|
|
345
|
-
// 2) `.next/static` →
|
|
346
|
-
//
|
|
347
|
-
//
|
|
348
|
-
// standalone e mergeiam na extração.
|
|
379
|
+
// 2) `.next/static` → `./<prefixo>.next/static` (Next.js não copia sozinho).
|
|
380
|
+
// Forward-slash no membro é aceito por bsdtar e GNU tar, e casa com o
|
|
381
|
+
// `.next` já vindo do standalone — mergeiam na extração.
|
|
349
382
|
if (fileExists(staticDir)) {
|
|
350
|
-
args.push('-C', norm(
|
|
383
|
+
args.push('-C', norm(injecao.chdir), `${injecao.prefixo}.next/static`);
|
|
351
384
|
}
|
|
352
|
-
// 3) `public` →
|
|
385
|
+
// 3) `public` → `./<prefixo>public` (idem — não vem no standalone).
|
|
353
386
|
if (fileExists(publicDir)) {
|
|
354
|
-
args.push('-C', norm(
|
|
387
|
+
args.push('-C', norm(injecao.chdir), `${injecao.prefixo}public`);
|
|
355
388
|
}
|
|
356
389
|
try {
|
|
357
390
|
await runCmd('tar', args, process.cwd(), undefined, quiet);
|
|
@@ -456,70 +489,73 @@ function parseUnixEnvPrefix(script) {
|
|
|
456
489
|
* linha vazia (ignorada)
|
|
457
490
|
*
|
|
458
491
|
* Não suporta multi-line values — use aspas com \n.
|
|
492
|
+
*
|
|
493
|
+
* Revisão do cli#81 (N-r3-1): o arquivo é lido em bytes e só segue se for
|
|
494
|
+
* UTF-8 (`decodificarUtf8`). Antes, `readFile(…, 'utf8')` trocava cada byte
|
|
495
|
+
* que não é UTF-8 por U+FFFD sem aviso, e um .env ANSI com `NOME_LOJA=Café`
|
|
496
|
+
* entrava no build como `Caf\uFFFD`. A recusa é `CodificacaoInvalida`, que
|
|
497
|
+
* `runBuild` mostra como `invalid_encoding`.
|
|
459
498
|
*/
|
|
460
499
|
async function loadEnvFile(envFile) {
|
|
461
|
-
let
|
|
500
|
+
let bruto;
|
|
462
501
|
try {
|
|
463
|
-
|
|
502
|
+
bruto = await fsp.readFile(envFile);
|
|
464
503
|
}
|
|
465
504
|
catch {
|
|
466
505
|
throw new Error(`--env-file: arquivo não encontrado: ${envFile}`);
|
|
467
506
|
}
|
|
468
|
-
|
|
469
|
-
for (const line of content.split(/\r?\n/)) {
|
|
470
|
-
const trimmed = line.trim();
|
|
471
|
-
if (!trimmed || trimmed.startsWith('#'))
|
|
472
|
-
continue;
|
|
473
|
-
const eq = trimmed.indexOf('=');
|
|
474
|
-
if (eq === -1)
|
|
475
|
-
continue;
|
|
476
|
-
const key = trimmed.slice(0, eq).trim();
|
|
477
|
-
let val = trimmed.slice(eq + 1).trim();
|
|
478
|
-
// Remove aspas simétricas.
|
|
479
|
-
if (val.length >= 2) {
|
|
480
|
-
const open = val[0];
|
|
481
|
-
const close = val[val.length - 1];
|
|
482
|
-
if ((open === '"' && close === '"') || (open === "'" && close === "'")) {
|
|
483
|
-
val = val.slice(1, -1);
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
if (!key)
|
|
487
|
-
continue;
|
|
488
|
-
vars[key] = val;
|
|
489
|
-
}
|
|
490
|
-
return vars;
|
|
507
|
+
return variaveisDoEnvFile(semBomInicial(decodificarUtf8(bruto, 'env-file')));
|
|
491
508
|
}
|
|
492
|
-
async function buildNode(cwd, noCache, noInstall = false, extraEnv, targetEnv = 'prod', quiet = false
|
|
509
|
+
async function buildNode(cwd, noCache, noInstall = false, extraEnv, targetEnv = 'prod', quiet = false,
|
|
510
|
+
// bug_678ddc98: o gerenciador de pacote deixa de ser `npm` cravado. Quem
|
|
511
|
+
// chama já detectou (lockfile/campo packageManager) e passa aqui — default
|
|
512
|
+
// mantém o comportamento histórico pra qualquer caller que não passe nada.
|
|
513
|
+
pm = { name: 'npm', rootDir: cwd, source: 'default' }) {
|
|
493
514
|
const lg = scopedLog(quiet);
|
|
494
515
|
const pkgPath = path.join(cwd, 'package.json');
|
|
495
516
|
if (!fileExists(pkgPath))
|
|
496
517
|
throw new Error('Stack node sem package.json.');
|
|
497
518
|
const pkg = JSON.parse(await fsp.readFile(pkgPath, 'utf8'));
|
|
519
|
+
const install = comandoInstall(pm.name);
|
|
520
|
+
const runBuildScript = comandoRunScript(pm.name, 'build');
|
|
498
521
|
// bug_93f984a (MEDIUM): npm ci conflita com `next dev` em Windows (file locks
|
|
499
522
|
// em node_modules/@next/swc-*). Trocar pra `npm install --no-save --no-audit
|
|
500
523
|
// --no-fund` que respeita locks parciais. Flag --no-install permite skip
|
|
501
524
|
// total quando dev sabe que node_modules está OK.
|
|
502
525
|
if (noInstall) {
|
|
503
|
-
lg.dim(
|
|
526
|
+
lg.dim(`${install.cmd} install pulado (--no-install).`);
|
|
504
527
|
}
|
|
505
528
|
else {
|
|
506
529
|
if (noCache) {
|
|
507
530
|
// BUG-016 fix (2026-05-13): não apagar package-lock.json do usuário.
|
|
508
531
|
// Em vez disso, limpamos o cache do npm global se `--no-cache` for exigido.
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
532
|
+
// bug_678ddc98: `cache clean --force` é sintaxe de npm/pnpm; yarn e bun
|
|
533
|
+
// usam outra, então pros dois a limpeza é pulada (nunca é fatal — o
|
|
534
|
+
// --no-cache continua valendo pro caminho docker).
|
|
535
|
+
if (pm.name === 'npm' || pm.name === 'pnpm') {
|
|
536
|
+
lg.info(`Limpando cache do ${pm.name} (--no-cache)…`);
|
|
537
|
+
try {
|
|
538
|
+
await runCmd(pm.name, ['cache', 'clean', '--force'], cwd, undefined, quiet);
|
|
539
|
+
}
|
|
540
|
+
catch {
|
|
541
|
+
// Ignora falha de cache clean e prossegue
|
|
542
|
+
}
|
|
512
543
|
}
|
|
513
|
-
|
|
514
|
-
|
|
544
|
+
else {
|
|
545
|
+
lg.dim(` --no-cache ignorado: ${pm.name} não tem \`cache clean --force\`.`);
|
|
515
546
|
}
|
|
516
547
|
}
|
|
517
548
|
if (process.platform === 'win32') {
|
|
518
|
-
lg.warn(`Se houver \`next dev\` ativo na pasta, ele pode conflitar com o
|
|
549
|
+
lg.warn(`Se houver \`next dev\` ativo na pasta, ele pode conflitar com o ${install.cmd} install (file locks).\n` +
|
|
519
550
|
` Pause o dev server antes do build, ou use --no-install pra pular esta etapa.`);
|
|
520
551
|
}
|
|
521
|
-
|
|
522
|
-
|
|
552
|
+
// bug_678ddc98: o install roda na RAIZ do workspace (onde mora o lockfile),
|
|
553
|
+
// não no diretório do app — `pnpm install` dentro de `apps/web` sem o
|
|
554
|
+
// lockfile por perto instala um projeto solto e quebra os links dos pacotes
|
|
555
|
+
// internos. Em repo de app único `pm.rootDir === cwd` e nada muda.
|
|
556
|
+
lg.info(`${install.cmd} ${install.args.join(' ')} (não destrutivo, respeita locks)` +
|
|
557
|
+
`${pm.rootDir === cwd ? '' : ` em ${pm.rootDir}`}…`);
|
|
558
|
+
await runCmd(install.cmd, install.args, pm.rootDir, undefined, quiet);
|
|
523
559
|
}
|
|
524
560
|
if (pkg.scripts?.build) {
|
|
525
561
|
// Fix crítico (2026-07-22, incidente pdv-agiliza): `NEXT_PUBLIC_NEETRU_ENV`
|
|
@@ -546,13 +582,17 @@ async function buildNode(cwd, noCache, noInstall = false, extraEnv, targetEnv =
|
|
|
546
582
|
lg.info(`Script "build" usa env-prefix Unix. Auto-injetando ${Object.keys(mergedEnv).join('+')} via spawn-env (compat Windows).`);
|
|
547
583
|
lg.dim(` Original: ${pkg.scripts.build}`);
|
|
548
584
|
lg.dim(` Executando: ${cmd} (com env: ${JSON.stringify(mergedEnv)})`);
|
|
549
|
-
// Roda o comando real com env injetado
|
|
585
|
+
// Roda o comando real com env injetado, resolvendo bins de
|
|
550
586
|
// node_modules/.bin (next, vite, tsc, etc).
|
|
551
587
|
const parts = cmd.split(/\s+/);
|
|
552
588
|
const bin = parts[0];
|
|
553
589
|
const args = parts.slice(1);
|
|
554
|
-
// npx
|
|
555
|
-
|
|
590
|
+
// bug_678ddc98: `npx` era cravado aqui. Com pnpm isso é um tiro no pé —
|
|
591
|
+
// os bins ficam atrás do store de links e o npx acabaria BAIXANDO o
|
|
592
|
+
// pacote do registry em vez de usar o do workspace. `comandoExecBin`
|
|
593
|
+
// devolve `pnpm exec`/`yarn exec`/`bunx`/`npx` conforme o gerenciador.
|
|
594
|
+
const exec = comandoExecBin(pm.name, bin, args);
|
|
595
|
+
await runCmd(exec.cmd, exec.args, cwd, mergedEnv, quiet);
|
|
556
596
|
}
|
|
557
597
|
else {
|
|
558
598
|
const mergedEnv = { ...(extraEnv ?? {}), ...forcedEnv };
|
|
@@ -562,9 +602,11 @@ async function buildNode(cwd, noCache, noInstall = false, extraEnv, targetEnv =
|
|
|
562
602
|
lg.info(`Injetando ${Object.keys(extraEnv).length} var(s) de env-file: ${Object.keys(extraEnv).join(', ')}`);
|
|
563
603
|
}
|
|
564
604
|
else {
|
|
565
|
-
lg.info('
|
|
605
|
+
lg.info(`${runBuildScript.cmd} ${runBuildScript.args.join(' ')}…`);
|
|
566
606
|
}
|
|
567
|
-
|
|
607
|
+
// O BUILD roda no diretório do APP (não na raiz do workspace): é lá que
|
|
608
|
+
// mora o script `build` e é lá que o Next.js grava o `.next`.
|
|
609
|
+
await runCmd(runBuildScript.cmd, runBuildScript.args, cwd, mergedEnv, quiet);
|
|
568
610
|
}
|
|
569
611
|
}
|
|
570
612
|
// bug_b8e6e1a2: Next.js `output: 'standalone'` — a verdade pós-build é a pasta
|
|
@@ -572,8 +614,25 @@ async function buildNode(cwd, noCache, noInstall = false, extraEnv, targetEnv =
|
|
|
572
614
|
// Standalone roda via `node server.js` (com seu node_modules mínimo próprio),
|
|
573
615
|
// NUNCA `next start` — por isso o entrypoint muda pra `server.js` e o
|
|
574
616
|
// empacotamento pula o node_modules gigante da raiz.
|
|
617
|
+
const layout = resolveStandaloneLayout(cwd);
|
|
575
618
|
const standalone = isStandaloneBuildDir(cwd) || detectStandaloneOutput(cwd);
|
|
576
|
-
|
|
619
|
+
// bug_678ddc98: o entrypoint era a string FIXA `'server.js'`. Num monorepo o
|
|
620
|
+
// Next.js aninha o app dentro do standalone (`apps/web/server.js`) e esse
|
|
621
|
+
// caminho fixo apontava pro vazio. Agora vem do layout real pós-build.
|
|
622
|
+
if (standalone && isStandaloneBuildDir(cwd) && !layout) {
|
|
623
|
+
throw new Error('Existe `.next/standalone` mas nenhum `server.js` foi encontrado dentro dele. ' +
|
|
624
|
+
'Num monorepo o Next.js aninha o app sob o `outputFileTracingRoot` (ex: `apps/web/server.js`) — ' +
|
|
625
|
+
'confira se o build rodou no diretório certo (use `--app <dir>`) e se `output: "standalone"` está ativo. ' +
|
|
626
|
+
'Abortando: um tarball sem entrypoint sobe e nunca inicia.');
|
|
627
|
+
}
|
|
628
|
+
if (layout?.appPrefix) {
|
|
629
|
+
lg.dim(` standalone aninhado: entrypoint = ${layout.entrypoint} (monorepo — bug_678ddc98)`);
|
|
630
|
+
}
|
|
631
|
+
return {
|
|
632
|
+
entrypoint: standalone ? (layout?.entrypoint ?? 'server.js') : (pkg.main ?? 'index.js'),
|
|
633
|
+
standalone,
|
|
634
|
+
appPrefix: layout?.appPrefix ?? '',
|
|
635
|
+
};
|
|
577
636
|
}
|
|
578
637
|
/**
|
|
579
638
|
* `''`/whitespace/`null`/`undefined` num campo do manifesto contam como
|
|
@@ -714,9 +773,14 @@ async function buildPhp(cwd, quiet = false) {
|
|
|
714
773
|
}
|
|
715
774
|
return { entrypoint: 'index.php' };
|
|
716
775
|
}
|
|
717
|
-
async function buildStatic(cwd, noInstall = false, targetEnv = 'prod', quiet = false
|
|
776
|
+
async function buildStatic(cwd, noInstall = false, targetEnv = 'prod', quiet = false,
|
|
777
|
+
// bug_678ddc98: mesmo tratamento do stack node — um export estático também
|
|
778
|
+
// pode viver num monorepo pnpm/yarn.
|
|
779
|
+
pm = { name: 'npm', rootDir: cwd, source: 'default' }) {
|
|
718
780
|
const lg = scopedLog(quiet);
|
|
719
781
|
const pkgPath = path.join(cwd, 'package.json');
|
|
782
|
+
const install = comandoInstall(pm.name);
|
|
783
|
+
const runBuildScript = comandoRunScript(pm.name, 'build');
|
|
720
784
|
if (fileExists(pkgPath)) {
|
|
721
785
|
try {
|
|
722
786
|
const pkg = JSON.parse(await fsp.readFile(pkgPath, 'utf8'));
|
|
@@ -726,8 +790,9 @@ async function buildStatic(cwd, noInstall = false, targetEnv = 'prod', quiet = f
|
|
|
726
790
|
if (process.platform === 'win32') {
|
|
727
791
|
lg.warn('Se houver `next dev` ativo, pause antes (file locks).');
|
|
728
792
|
}
|
|
729
|
-
lg.info(
|
|
730
|
-
|
|
793
|
+
lg.info(`${install.cmd} ${install.args.join(' ')} (não destrutivo)…`);
|
|
794
|
+
// Install na raiz do workspace — ver o porquê em `buildNode`.
|
|
795
|
+
await runCmd(install.cmd, install.args, pm.rootDir, undefined, quiet);
|
|
731
796
|
}
|
|
732
797
|
// Fix (2026-07-22, achado da revisão adversarial): `--stack static`
|
|
733
798
|
// também roda `next build` (output:'export') pra produtos Next.js
|
|
@@ -735,8 +800,8 @@ async function buildStatic(cwd, noInstall = false, targetEnv = 'prod', quiet = f
|
|
|
735
800
|
// .env.production do stack node, mas sem proteção nenhuma até aqui.
|
|
736
801
|
// Mesmo forçado via spawn-env que buildNode (ver ali pro porquê).
|
|
737
802
|
lg.dim(` NEXT_PUBLIC_NEETRU_ENV forçado via spawn-env: ${targetEnv} (incidente pdv-agiliza 2026-07-22)`);
|
|
738
|
-
lg.info('
|
|
739
|
-
await runCmd(
|
|
803
|
+
lg.info(`${runBuildScript.cmd} ${runBuildScript.args.join(' ')}…`);
|
|
804
|
+
await runCmd(runBuildScript.cmd, runBuildScript.args, cwd, { NEXT_PUBLIC_NEETRU_ENV: targetEnv }, quiet);
|
|
740
805
|
}
|
|
741
806
|
}
|
|
742
807
|
catch {
|
|
@@ -760,8 +825,34 @@ export async function runBuild(opts = {}) {
|
|
|
760
825
|
const startedAt = Date.now();
|
|
761
826
|
if (!quiet)
|
|
762
827
|
log.banner();
|
|
763
|
-
|
|
764
|
-
|
|
828
|
+
// bug_678ddc98: duas noções de diretório, antes confundidas num `cwd` só.
|
|
829
|
+
//
|
|
830
|
+
// `invocacaoDir` = onde o dev rodou o comando. Manda no ARTEFATO: é onde
|
|
831
|
+
// sai o `.neetru-build/`, e é contra ele que os caminhos do manifest são
|
|
832
|
+
// relativizados. Precisa continuar assim porque o `neetru deploy` procura
|
|
833
|
+
// `<cwd>/.neetru-build/manifest.json` — se o artefato fosse pro diretório
|
|
834
|
+
// do app, um `neetru build --app apps/web && neetru deploy` da raiz não
|
|
835
|
+
// acharia nada.
|
|
836
|
+
// `cwd` (= diretório do APP) = onde mora o package.json a construir. Manda
|
|
837
|
+
// no BUILD: stack, versão, script `build`, `.next`, standalone, guard.
|
|
838
|
+
//
|
|
839
|
+
// Sem `--app` os dois são o mesmo diretório — comportamento idêntico ao de antes.
|
|
840
|
+
const invocacaoDir = process.cwd();
|
|
841
|
+
const cwd = path.resolve(invocacaoDir, opts.app ?? '.');
|
|
842
|
+
if (opts.app) {
|
|
843
|
+
if (!fileExists(cwd)) {
|
|
844
|
+
const msg = `--app "${opts.app}" não existe (resolvido para ${cwd}).`;
|
|
845
|
+
if (machineOutput)
|
|
846
|
+
emitBuildJsonError(msg, 'app_dir_not_found');
|
|
847
|
+
else
|
|
848
|
+
log.error(msg);
|
|
849
|
+
safeExit(1);
|
|
850
|
+
}
|
|
851
|
+
lg.dim(` app=${path.relative(invocacaoDir, cwd) || '.'} (monorepo — bug_678ddc98)`);
|
|
852
|
+
}
|
|
853
|
+
// O `neetru.config.json` pode morar no app (monorepo) ou na raiz do repo —
|
|
854
|
+
// procura nos dois, app primeiro (mais específico vence).
|
|
855
|
+
const localCfg = (await loadLocalConfig(cwd)) ?? (cwd === invocacaoDir ? null : await loadLocalConfig(invocacaoDir));
|
|
765
856
|
const slug = opts.product ?? localCfg?.slug;
|
|
766
857
|
if (!slug) {
|
|
767
858
|
const msg = '--product <slug> é obrigatório (ou rode em diretório com neetru.config.json).';
|
|
@@ -795,7 +886,7 @@ export async function runBuild(opts = {}) {
|
|
|
795
886
|
if (opts.targetEnv) {
|
|
796
887
|
const normalized = normalizeTarget(opts.targetEnv);
|
|
797
888
|
if (!normalized) {
|
|
798
|
-
const msg = `--target-env "${opts.targetEnv}" inválido. Use:
|
|
889
|
+
const msg = `--target-env "${opts.targetEnv}" inválido. Use: ${formatChoices(RUNTIME_ENVIRONMENT_IDS)}.`;
|
|
799
890
|
if (machineOutput)
|
|
800
891
|
emitBuildJsonError(msg, 'invalid_target_env');
|
|
801
892
|
else
|
|
@@ -808,27 +899,52 @@ export async function runBuild(opts = {}) {
|
|
|
808
899
|
// via spawn-env apenas durante o build — não vão pro Core nem ao manifest.
|
|
809
900
|
let buildEnvVars;
|
|
810
901
|
if (opts.envFile) {
|
|
811
|
-
|
|
812
|
-
|
|
902
|
+
// Resolvido contra o diretório de INVOCAÇÃO: o dev digitou o caminho a
|
|
903
|
+
// partir de onde ele está, não a partir do diretório do app.
|
|
904
|
+
const envFilePath = path.resolve(invocacaoDir, opts.envFile);
|
|
905
|
+
try {
|
|
906
|
+
buildEnvVars = await loadEnvFile(envFilePath);
|
|
907
|
+
}
|
|
908
|
+
catch (err) {
|
|
909
|
+
if (!(err instanceof CodificacaoInvalida))
|
|
910
|
+
throw err;
|
|
911
|
+
if (machineOutput)
|
|
912
|
+
emitBuildJsonError(err.message, 'invalid_encoding');
|
|
913
|
+
else
|
|
914
|
+
log.error(err.message);
|
|
915
|
+
safeExit(1);
|
|
916
|
+
}
|
|
813
917
|
lg.info(`Env-file carregado: ${opts.envFile} (${Object.keys(buildEnvVars).length} vars)`);
|
|
814
918
|
// Loga os nomes (nunca os valores) pra rastreabilidade sem vazar secrets.
|
|
815
919
|
lg.dim(` vars: ${Object.keys(buildEnvVars).join(', ')}`);
|
|
816
920
|
}
|
|
817
921
|
lg.heading(`neetru build`);
|
|
818
922
|
lg.dim(` slug=${slug} version=${version} stack=${stack}${rawStack === 'nextjs' ? ' (nextjs→node)' : ''}`);
|
|
819
|
-
|
|
923
|
+
// Artefato sai no diretório de INVOCAÇÃO (ver o bloco de `invocacaoDir`) —
|
|
924
|
+
// é o que mantém `neetru build --app apps/web && neetru deploy` funcionando
|
|
925
|
+
// a partir da raiz do monorepo.
|
|
926
|
+
const outputDir = path.resolve(invocacaoDir, opts.output ?? '.neetru-build');
|
|
820
927
|
await ensureDir(outputDir);
|
|
821
928
|
const tarballName = `${slug}-${version}.tar.gz`;
|
|
822
929
|
let tarballPath = path.join(outputDir, tarballName);
|
|
823
930
|
let entrypoint;
|
|
931
|
+
// bug_678ddc98 (elo que faltava): o layout aninhado era calculado, usado pro
|
|
932
|
+
// tar e DESCARTADO. O deploy precisa dele pra decidir se manda o entrypoint.
|
|
933
|
+
let appPrefix = '';
|
|
824
934
|
const spinner = registerSpinner(ora({ text: `Construindo ${stack}…`, color: 'blue' }).start());
|
|
825
935
|
try {
|
|
826
936
|
if (stack === 'node') {
|
|
827
937
|
// bug_25ff8581: passa extraEnv do --env-file para o buildNode.
|
|
828
938
|
// Incidente 2026-07-22: passa targetEnv — força NEXT_PUBLIC_NEETRU_ENV
|
|
829
939
|
// via spawn-env, neutralizando .env.local vencendo .env.production.
|
|
830
|
-
|
|
940
|
+
// bug_678ddc98: o gerenciador vem do lockfile/campo `packageManager`
|
|
941
|
+
// (npm/pnpm/yarn/bun), não mais cravado em `npm`.
|
|
942
|
+
const pm = detectPackageManager(cwd);
|
|
943
|
+
lg.dim(` gerenciador=${pm.name} (${pm.source}${pm.lockfile ? `: ${pm.lockfile}` : ''})` +
|
|
944
|
+
`${pm.rootDir === cwd ? '' : ` raiz-do-workspace=${path.relative(invocacaoDir, pm.rootDir) || '.'}`}`);
|
|
945
|
+
const r = await buildNode(cwd, !!opts.noCache, !!opts.noInstall, buildEnvVars, targetEnv, quiet, pm);
|
|
831
946
|
entrypoint = r.entrypoint;
|
|
947
|
+
appPrefix = r.appPrefix;
|
|
832
948
|
// Incidente 2026-07-22: confirma que o bundle compilado realmente
|
|
833
949
|
// refletiu o targetEnv (defesa contra scripts de build customizados
|
|
834
950
|
// que ignorem o spawn-env acima) ANTES de empacotar o tarball.
|
|
@@ -840,7 +956,10 @@ export async function runBuild(opts = {}) {
|
|
|
840
956
|
// agente da VM estourava o timeout de 120s de extração, bug_e3202fcc, e
|
|
841
957
|
// bloqueava o deploy). O standalone já traz seu node_modules mínimo.
|
|
842
958
|
lg.info('Next.js standalone detectado — empacotando output tracejado (sem node_modules da raiz).');
|
|
843
|
-
|
|
959
|
+
// bug_678ddc98: `appPrefix` leva `.next/static` e `public` pro lugar
|
|
960
|
+
// onde o `server.js` aninhado vai procurá-los. `''` = layout de app
|
|
961
|
+
// único, idêntico ao anterior.
|
|
962
|
+
await tarStandalone(cwd, tarballPath, ['*.log'], quiet, r.appPrefix);
|
|
844
963
|
}
|
|
845
964
|
else {
|
|
846
965
|
// Não-standalone: o servidor (`next start`/`node`) precisa do
|
|
@@ -869,7 +988,7 @@ export async function runBuild(opts = {}) {
|
|
|
869
988
|
else if (stack === 'static') {
|
|
870
989
|
// Incidente 2026-07-22: --stack static também roda `next build`
|
|
871
990
|
// (output:'export') pra produtos Next.js — mesma proteção do stack node.
|
|
872
|
-
const r = await buildStatic(cwd, !!opts.noInstall, targetEnv, quiet);
|
|
991
|
+
const r = await buildStatic(cwd, !!opts.noInstall, targetEnv, quiet, detectPackageManager(cwd));
|
|
873
992
|
entrypoint = r.entrypoint;
|
|
874
993
|
await validateBuildEnvManifest(cwd, targetEnv, quiet);
|
|
875
994
|
await tarDirectory(r.root, tarballPath, ['.git', '.neetru-build'], quiet);
|
|
@@ -877,7 +996,7 @@ export async function runBuild(opts = {}) {
|
|
|
877
996
|
else {
|
|
878
997
|
throw new Error(`Stack desconhecida: ${stack}`);
|
|
879
998
|
}
|
|
880
|
-
spinner.succeed(`Empacotado: ${chalk.bold(path.relative(
|
|
999
|
+
spinner.succeed(`Empacotado: ${chalk.bold(path.relative(invocacaoDir, tarballPath))}`);
|
|
881
1000
|
unregisterSpinner(spinner);
|
|
882
1001
|
}
|
|
883
1002
|
catch (err) {
|
|
@@ -913,17 +1032,20 @@ export async function runBuild(opts = {}) {
|
|
|
913
1032
|
version,
|
|
914
1033
|
// Gravamos o stack canônico (nextjs já foi normalizado acima).
|
|
915
1034
|
stack,
|
|
916
|
-
tarball: path.relative(
|
|
1035
|
+
tarball: path.relative(invocacaoDir, tarballPath),
|
|
917
1036
|
sha256,
|
|
918
1037
|
sizeBytes,
|
|
919
1038
|
entrypoint,
|
|
1039
|
+
// Só grava quando há aninhamento — manifest de app único fica idêntico ao
|
|
1040
|
+
// de antes (nenhuma chave nova), então nada a montante muda de forma.
|
|
1041
|
+
...(appPrefix ? { appPrefix } : {}),
|
|
920
1042
|
builtAt: new Date().toISOString(),
|
|
921
1043
|
};
|
|
922
1044
|
const manifestPath = path.join(outputDir, 'manifest.json');
|
|
923
1045
|
await fsp.writeFile(manifestPath, JSON.stringify(manifest, null, 2), 'utf8');
|
|
924
1046
|
lg.dim(` sha256=${sha256.slice(0, 16)}…`);
|
|
925
1047
|
lg.dim(` size=${(sizeBytes / 1024 / 1024).toFixed(2)} MB`);
|
|
926
|
-
lg.dim(` manifest=${path.relative(
|
|
1048
|
+
lg.dim(` manifest=${path.relative(invocacaoDir, manifestPath)}`);
|
|
927
1049
|
lg.success(`Build pronto. Use: ${chalk.bold('neetru deploy --product=' + slug)}`);
|
|
928
1050
|
// SETOR 5.1: em --json, imprime UMA linha JSON estruturada no stdout no fim.
|
|
929
1051
|
// Não emite quando chamado internamente pelo deploy (`quiet` sem `json`) — o
|
|
@@ -942,7 +1064,7 @@ export async function runBuild(opts = {}) {
|
|
|
942
1064
|
sizeBytes,
|
|
943
1065
|
entrypoint: entrypoint ?? null,
|
|
944
1066
|
builtAt: manifest.builtAt,
|
|
945
|
-
manifestPath: path.relative(
|
|
1067
|
+
manifestPath: path.relative(invocacaoDir, manifestPath),
|
|
946
1068
|
durationMs: Date.now() - startedAt,
|
|
947
1069
|
}));
|
|
948
1070
|
}
|
package/dist/commands/chat.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
|
+
import type { NeetruCliError } from '../cli-kit/errors.js';
|
|
2
3
|
type ActorType = 'agent_claude' | 'human' | 'cli';
|
|
3
4
|
type ChatChannelType = 'global' | 'product' | 'custom';
|
|
4
5
|
export interface ChatChannelsOptions {
|
|
@@ -44,6 +45,82 @@ export interface ChatIdentityOptions {
|
|
|
44
45
|
/** Suprime o log de sucesso (usado pelo --as do send). */
|
|
45
46
|
quiet?: boolean;
|
|
46
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* O que `neetru chat identity <args...>` pede.
|
|
50
|
+
*
|
|
51
|
+
* bug_09574d4b (2026-10-12): o comando só aceitava o apelido POSICIONAL, e não
|
|
52
|
+
* havia subcomando — mas a skill da casa (`neetru-chat`) documenta
|
|
53
|
+
* `identity set "Nome"` e `identity show`. Resultado: `identity show` GRAVAVA o
|
|
54
|
+
* apelido "show", e `identity set "PDV · IA"` gravava "set" e descartava o
|
|
55
|
+
* nome. Sem aviso: a saída era o mesmo "✓ Apelido definido" do caminho feliz.
|
|
56
|
+
*
|
|
57
|
+
* Agora `show`/`ver` lê, `set`/`definir` grava o resto, `clear`/`limpar` limpa,
|
|
58
|
+
* e o posicional antigo (`identity "PDV · IA"`) segue funcionando. O preço: não
|
|
59
|
+
* dá pra ter um apelido que seja SÓ uma dessas palavras.
|
|
60
|
+
*
|
|
61
|
+
* P105 (2026-10-18): o conserto acima cobria só as palavras que ele conhecia.
|
|
62
|
+
* `identity describe` gravava "describe", `identity list` gravava "list",
|
|
63
|
+
* `identity show Fulano` gravava "show Fulano" e `identity set clear` gravava
|
|
64
|
+
* "clear". Agora nenhum verbo de `identity` (os de `LER`/`DEFINIR`/`LIMPAR`)
|
|
65
|
+
* nem sinônimo de um deles (`SYNONYMS`, cli-kit) vira apelido: a CLI recusa e
|
|
66
|
+
* sugere o verbo certo, com o piso de qualidade do gcloud (`MIN_RATIO`) — sem
|
|
67
|
+
* sugestão que passe o piso, lista os três. Um apelido que só COMEÇA com um
|
|
68
|
+
* verbo continua possível pela forma explícita (`identity set "Show de Bola"`);
|
|
69
|
+
* um apelido que É um verbo (`Set`, `Ver`) só pelo `--as` do `send`, e a
|
|
70
|
+
* recusa ensina esse caminho.
|
|
71
|
+
*
|
|
72
|
+
* Os caminhos citados (`neetru chat identity …`, `neetru chat send --as`) saem
|
|
73
|
+
* da árvore do Commander (`contextoDeIdentidadeDaArvore`), não de literal
|
|
74
|
+
* (revisão do #87, BAIXO 5).
|
|
75
|
+
*/
|
|
76
|
+
export type PedidoDeIdentidade = {
|
|
77
|
+
acao: 'mostrar';
|
|
78
|
+
} | {
|
|
79
|
+
acao: 'definir';
|
|
80
|
+
apelido: string;
|
|
81
|
+
} | {
|
|
82
|
+
acao: 'erro';
|
|
83
|
+
mensagem: string;
|
|
84
|
+
erro?: NeetruCliError;
|
|
85
|
+
};
|
|
86
|
+
/** Caminho do comando na árvore, sem o `neetru` (ex.: `'chat channels create'`). */
|
|
87
|
+
export declare function caminhoDoComando(cmd: Command | null | undefined): string;
|
|
88
|
+
/** Onde `identity` mora na árvore e por onde se grava um apelido que é verbo. */
|
|
89
|
+
export interface ContextoDeIdentidade {
|
|
90
|
+
/** Caminho do `identity`, sem o `neetru`. */
|
|
91
|
+
comando: string;
|
|
92
|
+
/** Caminho do `send` que declara `--as`, ou `null` se a árvore não tem esse caminho. */
|
|
93
|
+
definirViaSend: string | null;
|
|
94
|
+
}
|
|
95
|
+
/** O que a árvore de verdade dá hoje — travado por teste contra `registerChatCommand`. */
|
|
96
|
+
export declare const CONTEXTO_DE_IDENTIDADE_PADRAO: ContextoDeIdentidade;
|
|
97
|
+
/** Deriva o contexto do nó `identity` do Commander (o que o `.action()` recebe). */
|
|
98
|
+
export declare function contextoDeIdentidadeDaArvore(identity: Command): ContextoDeIdentidade;
|
|
99
|
+
export declare function interpretarArgsDeIdentidade(args: readonly string[], ctx?: ContextoDeIdentidade): PedidoDeIdentidade;
|
|
100
|
+
/**
|
|
101
|
+
* Texto livre POSICIONAL de uma palavra só que é SUBCOMANDO irmão (nome,
|
|
102
|
+
* apelido ou sinônimo): recusa (P105). `neetru chat send history` postava
|
|
103
|
+
* "history" no canal global achando que listava; `neetru chat channels create
|
|
104
|
+
* close` criava o canal "close". Os subcomandos e o caminho citados saem do
|
|
105
|
+
* nó do Commander em execução (`command`), não de literal.
|
|
106
|
+
*
|
|
107
|
+
* `null` quando o texto pode seguir: resposta comum (`show`, `ok`, `top`,
|
|
108
|
+
* `beleza`, `valeu`, `sim`, `blz` — revisão do #87, BAIXO 6) e frase que só
|
|
109
|
+
* começa com uma palavra de comando ("history do dia").
|
|
110
|
+
*/
|
|
111
|
+
export declare function verboComoTextoPosicional(input: {
|
|
112
|
+
texto: string;
|
|
113
|
+
command: Command;
|
|
114
|
+
oQue: string;
|
|
115
|
+
escapeHint?: string;
|
|
116
|
+
}): NeetruCliError | null;
|
|
117
|
+
interface ChatIdentityResponse {
|
|
118
|
+
ok: true;
|
|
119
|
+
/** Apelido atual (string vazia = nenhum). */
|
|
120
|
+
displayName: string;
|
|
121
|
+
/** Email da credencial — só no GET. */
|
|
122
|
+
email?: string;
|
|
123
|
+
}
|
|
47
124
|
/**
|
|
48
125
|
* `neetru chat identity [apelido]` — apelido inerente à credencial (CH3).
|
|
49
126
|
*
|
|
@@ -55,7 +132,23 @@ export interface ChatIdentityOptions {
|
|
|
55
132
|
* O apelido vive em `cli_api_keys/{keyId}.displayName` — é inerente ao token,
|
|
56
133
|
* não por-mensagem.
|
|
57
134
|
*/
|
|
58
|
-
export declare function runChatIdentity(displayName: string | undefined, opts?: ChatIdentityOptions): Promise<
|
|
135
|
+
export declare function runChatIdentity(displayName: string | undefined, opts?: ChatIdentityOptions): Promise<ChatIdentityResponse | undefined>;
|
|
136
|
+
/**
|
|
137
|
+
* `chat send --as <apelido>`.
|
|
138
|
+
*
|
|
139
|
+
* O Core NÃO tem apelido por mensagem — o nome vem da credencial
|
|
140
|
+
* (`cli_api_keys/{keyId}.displayName`). Então `--as` só pode PERSISTIR. O defeito
|
|
141
|
+
* (bug_09574d4b) não era persistir: era persistir CALADO — e o help da versão
|
|
142
|
+
* publicada dizia só "antes de enviar", então quem lia concluía, com razão, que
|
|
143
|
+
* valia para aquela mensagem. Credencial compartilhada entre sessões fazia uma
|
|
144
|
+
* renomear a outra sem ninguém ver.
|
|
145
|
+
*
|
|
146
|
+
* Agora: se o apelido já é o pedido, nada muda (nem chamada de escrita); se muda,
|
|
147
|
+
* o aviso vai pro STDERR dizendo de quem para quem e que vale para as próximas
|
|
148
|
+
* mensagens da credencial. STDERR porque em `--json` o stdout é contrato de uma
|
|
149
|
+
* linha.
|
|
150
|
+
*/
|
|
151
|
+
export declare function aplicarApelidoDoSend(apelidoBruto: string, json: boolean): Promise<void>;
|
|
59
152
|
export interface ChatHistoryOptions {
|
|
60
153
|
/** Canal de destino (novo — tem precedência sobre product). */
|
|
61
154
|
channel?: string;
|