@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.
Files changed (245) hide show
  1. package/CHANGELOG.md +99 -2
  2. package/README.md +2 -0
  3. package/dist/cli-kit/choices.d.ts +33 -0
  4. package/dist/cli-kit/choices.js +32 -0
  5. package/dist/cli-kit/command-context.d.ts +98 -0
  6. package/dist/cli-kit/command-context.js +108 -0
  7. package/dist/cli-kit/errors.d.ts +79 -0
  8. package/dist/cli-kit/errors.js +94 -0
  9. package/dist/cli-kit/index.d.ts +8 -0
  10. package/dist/cli-kit/index.js +8 -0
  11. package/dist/cli-kit/suggest.d.ts +74 -0
  12. package/dist/cli-kit/suggest.js +207 -0
  13. package/dist/commands/admin/oidc-login.js +1 -1
  14. package/dist/commands/admin/sdk-credential.js +1 -1
  15. package/dist/commands/autocomplete.d.ts +1 -1
  16. package/dist/commands/autocomplete.js +1 -0
  17. package/dist/commands/bug.d.ts +59 -0
  18. package/dist/commands/bug.js +118 -6
  19. package/dist/commands/build.d.ts +24 -1
  20. package/dist/commands/build.js +195 -73
  21. package/dist/commands/chat.d.ts +94 -1
  22. package/dist/commands/chat.js +258 -26
  23. package/dist/commands/customers.js +1 -1
  24. package/dist/commands/db-move.js +3 -3
  25. package/dist/commands/db.js +20 -33
  26. package/dist/commands/deploy.d.ts +91 -2
  27. package/dist/commands/deploy.js +423 -78
  28. package/dist/commands/deployments.js +11 -6
  29. package/dist/commands/dev-context.js +15 -5
  30. package/dist/commands/docs-produto.d.ts +25 -0
  31. package/dist/commands/docs-produto.js +70 -8
  32. package/dist/commands/doctor.js +36 -1
  33. package/dist/commands/domains.js +85 -4
  34. package/dist/commands/env.d.ts +9 -3
  35. package/dist/commands/env.js +23 -3
  36. package/dist/commands/infra-read.js +2 -2
  37. package/dist/commands/init.js +8 -1
  38. package/dist/commands/login.js +35 -8
  39. package/dist/commands/logs.js +12 -4
  40. package/dist/commands/mobile.js +33 -9
  41. package/dist/commands/new.d.ts +29 -1
  42. package/dist/commands/new.js +92 -4
  43. package/dist/commands/open.js +16 -6
  44. package/dist/commands/ops.js +1 -1
  45. package/dist/commands/products-db.d.ts +1 -0
  46. package/dist/commands/products-db.js +41 -8
  47. package/dist/commands/products.d.ts +17 -3
  48. package/dist/commands/products.js +86 -18
  49. package/dist/commands/promote.js +30 -5
  50. package/dist/commands/secrets.d.ts +91 -0
  51. package/dist/commands/secrets.js +471 -0
  52. package/dist/commands/servers.js +8 -5
  53. package/dist/commands/status.js +2 -2
  54. package/dist/commands/support.js +5 -3
  55. package/dist/commands/tenants.js +28 -16
  56. package/dist/commands/upgrade.d.ts +9 -0
  57. package/dist/commands/upgrade.js +50 -1
  58. package/dist/commands/vm-memory.js +1 -0
  59. package/dist/commands/webhooks.d.ts +2 -0
  60. package/dist/commands/webhooks.js +9 -3
  61. package/dist/commands/workspaces.js +42 -11
  62. package/dist/index.js +70 -14
  63. package/dist/lib/api-client.d.ts +14 -0
  64. package/dist/lib/api-client.js +59 -6
  65. package/dist/lib/api-error.d.ts +14 -0
  66. package/dist/lib/api-error.js +107 -46
  67. package/dist/lib/build-targets.d.ts +127 -0
  68. package/dist/lib/build-targets.js +348 -0
  69. package/dist/lib/cli-error.d.ts +13 -0
  70. package/dist/lib/cli-error.js +24 -0
  71. package/dist/lib/cli-write.d.ts +43 -9
  72. package/dist/lib/cli-write.js +154 -45
  73. package/dist/lib/config-schema.d.ts +8 -8
  74. package/dist/lib/db-local/db-json.d.ts +1 -1
  75. package/dist/lib/db-local/db-json.js +13 -5
  76. package/dist/lib/db-local/env.d.ts +15 -3
  77. package/dist/lib/db-local/env.js +37 -10
  78. package/dist/lib/db-pipeline/build-deps.d.ts +5 -1
  79. package/dist/lib/db-pipeline/build-deps.js +23 -3
  80. package/dist/lib/db-pipeline/types.d.ts +6 -2
  81. package/dist/lib/db-pipeline/types.js +0 -18
  82. package/dist/lib/deploy-target-contract.d.ts +152 -0
  83. package/dist/lib/deploy-target-contract.js +411 -0
  84. package/dist/lib/env-file-do-build.d.ts +19 -0
  85. package/dist/lib/env-file-do-build.js +44 -0
  86. package/dist/lib/envs.d.ts +108 -0
  87. package/dist/lib/envs.js +127 -0
  88. package/dist/lib/fs-seguro.d.ts +63 -0
  89. package/dist/lib/fs-seguro.js +108 -0
  90. package/dist/lib/inquirer-sob-demanda.d.ts +14 -0
  91. package/dist/lib/inquirer-sob-demanda.js +18 -0
  92. package/dist/lib/mobile-local/mobile-json.js +10 -4
  93. package/dist/lib/pickers.d.ts +44 -7
  94. package/dist/lib/pickers.js +65 -7
  95. package/dist/lib/product-docs/sync.d.ts +6 -0
  96. package/dist/lib/product-docs/sync.js +10 -1
  97. package/dist/lib/public-secret-scan.d.ts +44 -3
  98. package/dist/lib/public-secret-scan.js +361 -36
  99. package/dist/lib/render.d.ts +16 -0
  100. package/dist/lib/render.js +34 -4
  101. package/dist/lib/segredo-produto.d.ts +124 -0
  102. package/dist/lib/segredo-produto.js +336 -0
  103. package/dist/lib/texto-utf8.d.ts +96 -0
  104. package/dist/lib/texto-utf8.js +196 -0
  105. package/package.json +2 -1
  106. package/dist/cli-kit/format.js.map +0 -1
  107. package/dist/cli-kit/glyphs.js.map +0 -1
  108. package/dist/cli-kit/index.js.map +0 -1
  109. package/dist/cli-kit/palette.js.map +0 -1
  110. package/dist/commands/add.js.map +0 -1
  111. package/dist/commands/admin/iam-check.js.map +0 -1
  112. package/dist/commands/admin/oidc-login.js.map +0 -1
  113. package/dist/commands/admin/sdk-credential.js.map +0 -1
  114. package/dist/commands/agent-release.js.map +0 -1
  115. package/dist/commands/agent-write.js.map +0 -1
  116. package/dist/commands/ai-models.js.map +0 -1
  117. package/dist/commands/ai.js.map +0 -1
  118. package/dist/commands/api-catalog.js.map +0 -1
  119. package/dist/commands/archive.js.map +0 -1
  120. package/dist/commands/artifact-registry.js.map +0 -1
  121. package/dist/commands/audit.js.map +0 -1
  122. package/dist/commands/auth.js.map +0 -1
  123. package/dist/commands/autocomplete.js.map +0 -1
  124. package/dist/commands/billing.js.map +0 -1
  125. package/dist/commands/bootstrap.js.map +0 -1
  126. package/dist/commands/bug.js.map +0 -1
  127. package/dist/commands/build.js.map +0 -1
  128. package/dist/commands/chat-menu.js.map +0 -1
  129. package/dist/commands/chat.js.map +0 -1
  130. package/dist/commands/cloud-run.js.map +0 -1
  131. package/dist/commands/code.js.map +0 -1
  132. package/dist/commands/config.js.map +0 -1
  133. package/dist/commands/customers.js.map +0 -1
  134. package/dist/commands/db-move.js.map +0 -1
  135. package/dist/commands/db.js.map +0 -1
  136. package/dist/commands/deploy.js.map +0 -1
  137. package/dist/commands/deployments.js.map +0 -1
  138. package/dist/commands/dev-context.js.map +0 -1
  139. package/dist/commands/dev-up.js.map +0 -1
  140. package/dist/commands/dev.js.map +0 -1
  141. package/dist/commands/docs-produto.js.map +0 -1
  142. package/dist/commands/docs.js.map +0 -1
  143. package/dist/commands/doctor.js.map +0 -1
  144. package/dist/commands/domains.js.map +0 -1
  145. package/dist/commands/dr.js.map +0 -1
  146. package/dist/commands/env.js.map +0 -1
  147. package/dist/commands/hosting-write.js.map +0 -1
  148. package/dist/commands/infra-read.js.map +0 -1
  149. package/dist/commands/init.js.map +0 -1
  150. package/dist/commands/login.js.map +0 -1
  151. package/dist/commands/logout.js.map +0 -1
  152. package/dist/commands/logs.js.map +0 -1
  153. package/dist/commands/mobile.js.map +0 -1
  154. package/dist/commands/mocks.js.map +0 -1
  155. package/dist/commands/new.js.map +0 -1
  156. package/dist/commands/open.js.map +0 -1
  157. package/dist/commands/ops.js.map +0 -1
  158. package/dist/commands/products-db.js.map +0 -1
  159. package/dist/commands/products.js.map +0 -1
  160. package/dist/commands/promote.js.map +0 -1
  161. package/dist/commands/publish.js.map +0 -1
  162. package/dist/commands/schema.js.map +0 -1
  163. package/dist/commands/servers.js.map +0 -1
  164. package/dist/commands/smoke.js.map +0 -1
  165. package/dist/commands/status.js.map +0 -1
  166. package/dist/commands/support.js.map +0 -1
  167. package/dist/commands/surface-status.js.map +0 -1
  168. package/dist/commands/tenants.js.map +0 -1
  169. package/dist/commands/ui.js.map +0 -1
  170. package/dist/commands/upgrade.js.map +0 -1
  171. package/dist/commands/validate.js.map +0 -1
  172. package/dist/commands/vm-memory.js.map +0 -1
  173. package/dist/commands/vm.js.map +0 -1
  174. package/dist/commands/webhooks.js.map +0 -1
  175. package/dist/commands/whoami.js.map +0 -1
  176. package/dist/commands/workspaces.js.map +0 -1
  177. package/dist/index.js.map +0 -1
  178. package/dist/lib/agent-artifact-url.js.map +0 -1
  179. package/dist/lib/agent-commands.js.map +0 -1
  180. package/dist/lib/ai/auth-discovery.js.map +0 -1
  181. package/dist/lib/ai/context.js.map +0 -1
  182. package/dist/lib/ai/orchestrator.js.map +0 -1
  183. package/dist/lib/api-client.js.map +0 -1
  184. package/dist/lib/api-error.js.map +0 -1
  185. package/dist/lib/auth.js.map +0 -1
  186. package/dist/lib/cli-read.js.map +0 -1
  187. package/dist/lib/cli-write.js.map +0 -1
  188. package/dist/lib/code-agent-budget.js.map +0 -1
  189. package/dist/lib/code-agent-files.js.map +0 -1
  190. package/dist/lib/code-agent-gateway.js.map +0 -1
  191. package/dist/lib/code-agent-git-tools.js.map +0 -1
  192. package/dist/lib/code-agent-protocol.js.map +0 -1
  193. package/dist/lib/code-agent-session.js.map +0 -1
  194. package/dist/lib/code-agent-settings.js.map +0 -1
  195. package/dist/lib/code-agent-skills.js.map +0 -1
  196. package/dist/lib/code-agent-subagents.js.map +0 -1
  197. package/dist/lib/code-agent-tools.js.map +0 -1
  198. package/dist/lib/code-agent-tui.js.map +0 -1
  199. package/dist/lib/code-agent-types.js.map +0 -1
  200. package/dist/lib/code-agent-ui.js.map +0 -1
  201. package/dist/lib/code-agent-web-tools.js.map +0 -1
  202. package/dist/lib/code-agent-write-tools.js.map +0 -1
  203. package/dist/lib/compose-generator.js.map +0 -1
  204. package/dist/lib/config-schema.js.map +0 -1
  205. package/dist/lib/config.js.map +0 -1
  206. package/dist/lib/db-local/db-json.js.map +0 -1
  207. package/dist/lib/db-local/env.js.map +0 -1
  208. package/dist/lib/db-local/fingerprint.js.map +0 -1
  209. package/dist/lib/db-local/index.js.map +0 -1
  210. package/dist/lib/db-pipeline/build-deps.js.map +0 -1
  211. package/dist/lib/db-pipeline/errors.js.map +0 -1
  212. package/dist/lib/db-pipeline/index.js.map +0 -1
  213. package/dist/lib/db-pipeline/pipeline.js.map +0 -1
  214. package/dist/lib/db-pipeline/rehearse.js.map +0 -1
  215. package/dist/lib/db-pipeline/types.js.map +0 -1
  216. package/dist/lib/dev-local-context.js.map +0 -1
  217. package/dist/lib/iam-preflight.js.map +0 -1
  218. package/dist/lib/mobile-local/index.js.map +0 -1
  219. package/dist/lib/mobile-local/mobile-json.js.map +0 -1
  220. package/dist/lib/pickers.js.map +0 -1
  221. package/dist/lib/product-config.js.map +0 -1
  222. package/dist/lib/product-docs/check.js.map +0 -1
  223. package/dist/lib/product-docs/config.js.map +0 -1
  224. package/dist/lib/product-docs/dates.js.map +0 -1
  225. package/dist/lib/product-docs/frontmatter.js.map +0 -1
  226. package/dist/lib/product-docs/git.js.map +0 -1
  227. package/dist/lib/product-docs/markdown.js.map +0 -1
  228. package/dist/lib/product-docs/ops.js.map +0 -1
  229. package/dist/lib/product-docs/structure.js.map +0 -1
  230. package/dist/lib/product-docs/sync.js.map +0 -1
  231. package/dist/lib/product-docs/taxonomy.js.map +0 -1
  232. package/dist/lib/product-docs/templates.js.map +0 -1
  233. package/dist/lib/public-secret-scan.js.map +0 -1
  234. package/dist/lib/render.js.map +0 -1
  235. package/dist/lib/schema-cache.js.map +0 -1
  236. package/dist/lib/sse.js.map +0 -1
  237. package/dist/lib/telemetry.js.map +0 -1
  238. package/dist/lib/token-resolver.js.map +0 -1
  239. package/dist/lib/url-allowlist.js.map +0 -1
  240. package/dist/lib/version-check.js.map +0 -1
  241. package/dist/utils/logger.js.map +0 -1
  242. package/dist/utils/logo.js.map +0 -1
  243. package/dist/utils/safe-exit.js.map +0 -1
  244. package/dist/utils/spinner-registry.js.map +0 -1
  245. package/dist/version.js.map +0 -1
@@ -0,0 +1,127 @@
1
+ export type PackageManagerName = 'npm' | 'pnpm' | 'yarn' | 'bun';
2
+ export interface PackageManagerInfo {
3
+ name: PackageManagerName;
4
+ /**
5
+ * Diretório onde o `install` deve rodar. Em monorepo é a RAIZ do workspace
6
+ * (onde mora o lockfile), não o diretório do app — `pnpm install` dentro de
7
+ * `apps/web` sem o lockfile por perto instala um projeto solto e quebra os
8
+ * links dos pacotes internos do workspace.
9
+ */
10
+ rootDir: string;
11
+ /** De onde veio a decisão — entra no log pra o dev conseguir auditar. */
12
+ source: 'campo packageManager' | 'lockfile' | 'default';
13
+ /** Lockfile encontrado (basename), quando `source === 'lockfile'`. */
14
+ lockfile?: string;
15
+ }
16
+ /**
17
+ * `packageManager: "pnpm@9.1.0"` (padrão corepack) → `'pnpm'`.
18
+ * Qualquer coisa fora do enum conhecido devolve `null` em vez de chutar.
19
+ */
20
+ export declare function parseCampoPackageManager(valor: unknown): PackageManagerName | null;
21
+ /**
22
+ * Um diretório só conta como RAIZ DE WORKSPACE se ele se declara como tal.
23
+ *
24
+ * Isso é a trava contra o pior modo de falha da subida na árvore: um app em
25
+ * `~/projetos/meu-app` sem lockfile próprio NÃO pode herdar o
26
+ * `package-lock.json` que por acaso existe em `~/projetos` — instalar lá
27
+ * mexeria num projeto que não é o do build.
28
+ */
29
+ export declare function ehRaizDeWorkspace(dir: string): boolean;
30
+ /**
31
+ * Descobre QUAL gerenciador de pacote usar e ONDE rodar o `install`, partindo
32
+ * do diretório do app.
33
+ *
34
+ * Ordem de decisão (da mais forte pra mais fraca):
35
+ * 1. `packageManager` no package.json do próprio app (corepack) — é uma
36
+ * declaração explícita do dono do projeto;
37
+ * 2. lockfile NO PRÓPRIO diretório do app (repo de app único);
38
+ * 3. subindo a árvore: o primeiro ancestral que tem lockfile **e** se declara
39
+ * raiz de workspace (`pnpm-workspace.yaml` ou `workspaces` no package.json).
40
+ * O `packageManager` desse ancestral, se houver, vence o lockfile dele;
41
+ * 4. nada encontrado → `npm` no próprio diretório do app (comportamento
42
+ * histórico — não quebra ninguém que já usava o CLI).
43
+ *
44
+ * A subida PARA no diretório que contém `.git` (inclusive): fora do repo não
45
+ * existe workspace que interesse a este build.
46
+ */
47
+ export declare function detectPackageManager(appDir: string): PackageManagerInfo;
48
+ export interface Comando {
49
+ cmd: string;
50
+ args: string[];
51
+ }
52
+ /**
53
+ * `install` NÃO-DESTRUTIVO por gerenciador.
54
+ *
55
+ * bug_93f984a já tinha estabelecido a regra pro npm: nunca `npm ci` (apaga
56
+ * node_modules e briga com os file locks do `next dev` no Windows). A mesma
57
+ * regra vale pros outros — nada de `--frozen-lockfile` nem `--immutable`, que
58
+ * falham de cara quando o dev acabou de mexer num package.json do workspace.
59
+ */
60
+ export declare function comandoInstall(pm: PackageManagerName): Comando;
61
+ /** Roda um script do package.json (`build`, `start`, …). */
62
+ export declare function comandoRunScript(pm: PackageManagerName, script: string): Comando;
63
+ /**
64
+ * Executa um binário de `node_modules/.bin` (`next`, `vite`, `tsc`…).
65
+ *
66
+ * Usado só no caminho Windows do bug_0cf14fba/bug_893891f, onde o CLI desmonta
67
+ * o prefixo de env estilo Unix do script e roda o comando real direto. Com pnpm
68
+ * o `npx` NÃO serve: os binários ficam atrás do store de links do pnpm e o npx
69
+ * acabaria BAIXANDO o pacote do registry em vez de usar o local.
70
+ */
71
+ export declare function comandoExecBin(pm: PackageManagerName, bin: string, args: string[]): Comando;
72
+ export interface LayoutStandalone {
73
+ /** `<appDir>/.next/standalone` — sempre a RAIZ do tar. */
74
+ standaloneDir: string;
75
+ /**
76
+ * Caminho POSIX do app DENTRO do standalone. `''` em repo de app único;
77
+ * `'apps/web'` num monorepo com `outputFileTracingRoot` na raiz.
78
+ */
79
+ appPrefix: string;
80
+ /** Entrypoint relativo à raiz do tar: `server.js` ou `apps/web/server.js`. */
81
+ entrypoint: string;
82
+ }
83
+ /**
84
+ * Acha ONDE o `server.js` do Next.js ficou dentro de `.next/standalone`.
85
+ *
86
+ * Em repo de app único ele está na raiz; em monorepo o Next.js aninha o app sob
87
+ * o caminho dele relativo ao `outputFileTracingRoot` (`apps/web/server.js`).
88
+ * Não dá pra deduzir esse prefixo do `next.config` (o `outputFileTracingRoot`
89
+ * pode ser implícito, vindo da detecção de workspace do próprio Next.js), então
90
+ * a verdade é a árvore PÓS-BUILD — a mesma lógica do `isStandaloneBuildDir`.
91
+ *
92
+ * Varredura em largura, pulando `node_modules` (pacote dependente pode ter um
93
+ * `server.js` qualquer e envenenar a busca). Entre candidatos, ganha o que
94
+ * TAMBÉM tem um diretório `.next` ao lado — é o par que o Next.js sempre emite
95
+ * junto (`server.js` + `.next/` com os chunks de servidor). Empate real resolve
96
+ * pelo mais raso e, em seguida, por ordem alfabética (determinismo: dois builds
97
+ * da mesma árvore têm que dar o mesmo tarball).
98
+ *
99
+ * Devolve `null` quando não há standalone nenhum (build não-standalone) ou
100
+ * quando há standalone mas nenhum `server.js` — nesse segundo caso quem chama
101
+ * precisa FALHAR, nunca empacotar um tarball sem entrypoint.
102
+ */
103
+ export declare function resolveStandaloneLayout(appDir: string): LayoutStandalone | null;
104
+ /**
105
+ * Resolve o `-C` do `tar` que faz `.next/static` e `public` caírem DENTRO do
106
+ * prefixo do app no tarball.
107
+ *
108
+ * O Next.js não copia nenhum dos dois pro standalone (limitação conhecida), e o
109
+ * runtime os procura ao lado do `server.js` — ou seja, dentro do prefixo do app,
110
+ * não na raiz do tar. Era exatamente isso que saía errado em monorepo
111
+ * (bug_678ddc98): o tar levava `./.next/static` e `./public` na raiz enquanto o
112
+ * server rodava de `apps/web/`, e o app subia sem CSS/JS e sem os estáticos.
113
+ *
114
+ * O truque pra gravar o membro já aninhado SEM `--transform` (GNU) nem `-s`
115
+ * (bsdtar), que não são portáveis entre os dois tars: o `appPrefix` é, por
116
+ * construção, `path.relative(outputFileTracingRoot, appDir)` — então o mesmo
117
+ * caminho EXISTE no disco a partir da raiz de tracing. Basta dar `-C <raiz de
118
+ * tracing>` e pedir o membro `apps/web/.next/static`, que o tar grava com o
119
+ * caminho completo.
120
+ *
121
+ * Devolve `null` quando o prefixo não casa com o disco (não deveria acontecer —
122
+ * é a trava contra empacotar caminho inventado).
123
+ */
124
+ export declare function baseDeInjecaoNoTar(appDir: string, appPrefix: string): {
125
+ chdir: string;
126
+ prefixo: string;
127
+ } | null;
@@ -0,0 +1,348 @@
1
+ /**
2
+ * Detecção de ALVO de build — o diretório do app, o gerenciador de pacote e o
3
+ * layout do output `standalone` do Next.js.
4
+ *
5
+ * bug_678ddc988497475d9160d714a5a10992: o `neetru build` nasceu assumindo
6
+ * "um repo = um app na raiz = npm". Três premissas, todas cravadas:
7
+ *
8
+ * 1. `cwd = process.cwd()` (build.ts:905) — não dava pra apontar pra um app
9
+ * dentro de `apps/<app>` sem `cd`;
10
+ * 2. `npm install` (build.ts:616) e `npm run build` (build.ts:664) literais —
11
+ * num repo pnpm/yarn isso resolve o workspace ERRADO (ou nem resolve);
12
+ * 3. `tarStandalone` assumia `.next/standalone/server.js` no TOPO e injetava
13
+ * `.next/static`/`public` na RAIZ do tar (build.ts:412-443), e o
14
+ * entrypoint era a string fixa `'server.js'` (build.ts:673).
15
+ *
16
+ * Num monorepo (pnpm workspaces + Turborepo) o Next.js, ao tracejar a partir
17
+ * de `outputFileTracingRoot`, ANINHA o app dentro do standalone:
18
+ *
19
+ * apps/web/.next/standalone/
20
+ * node_modules/… ← fica na RAIZ do standalone (tracejado/hoisted)
21
+ * packages/ui/… ← pacotes do workspace que o app importa
22
+ * apps/web/server.js ← o entrypoint REAL, aninhado
23
+ * apps/web/.next/…
24
+ *
25
+ * Por isso NÃO dá pra "re-enraizar" o tar em `apps/web`: `server.js` resolve
26
+ * `node_modules` subindo a árvore, e esses `node_modules` moram ACIMA dele.
27
+ * O formato correto é preservar a árvore inteira do standalone e apontar o
28
+ * entrypoint pro caminho aninhado (`apps/web/server.js`), injetando
29
+ * `.next/static` e `public` DENTRO do prefixo do app.
30
+ *
31
+ * Este módulo é propositalmente puro (só `fs` de leitura, zero subprocesso)
32
+ * pra ser testável sem rodar build nenhum.
33
+ */
34
+ import * as fs from 'node:fs';
35
+ import * as path from 'node:path';
36
+ /**
37
+ * Lockfiles conhecidos, em ordem de PRECEDÊNCIA dentro de um mesmo diretório.
38
+ *
39
+ * pnpm/yarn/bun vêm antes de npm de propósito: `package-lock.json` é o que mais
40
+ * aparece por acidente (um `npm install` distraído num repo pnpm gera um), então
41
+ * ele é o sinal MENOS confiável quando há concorrência. O campo `packageManager`
42
+ * do package.json (padrão corepack) ganha de todos — ver `detectPackageManager`.
43
+ */
44
+ const LOCKFILES = [
45
+ { file: 'pnpm-lock.yaml', name: 'pnpm' },
46
+ { file: 'yarn.lock', name: 'yarn' },
47
+ { file: 'bun.lockb', name: 'bun' },
48
+ { file: 'bun.lock', name: 'bun' },
49
+ { file: 'package-lock.json', name: 'npm' },
50
+ { file: 'npm-shrinkwrap.json', name: 'npm' },
51
+ ];
52
+ /** Teto de subida na árvore — monorepo nenhum aninha app a 12 níveis da raiz. */
53
+ const MAX_SUBIDA = 12;
54
+ function existe(p) {
55
+ try {
56
+ fs.statSync(p);
57
+ return true;
58
+ }
59
+ catch {
60
+ return false;
61
+ }
62
+ }
63
+ function lerJson(p) {
64
+ try {
65
+ return JSON.parse(fs.readFileSync(p, 'utf8'));
66
+ }
67
+ catch {
68
+ return null;
69
+ }
70
+ }
71
+ /**
72
+ * `packageManager: "pnpm@9.1.0"` (padrão corepack) → `'pnpm'`.
73
+ * Qualquer coisa fora do enum conhecido devolve `null` em vez de chutar.
74
+ */
75
+ export function parseCampoPackageManager(valor) {
76
+ if (typeof valor !== 'string')
77
+ return null;
78
+ const nome = valor.trim().split('@')[0].toLowerCase();
79
+ if (nome === 'npm' || nome === 'pnpm' || nome === 'yarn' || nome === 'bun')
80
+ return nome;
81
+ return null;
82
+ }
83
+ /**
84
+ * Um diretório só conta como RAIZ DE WORKSPACE se ele se declara como tal.
85
+ *
86
+ * Isso é a trava contra o pior modo de falha da subida na árvore: um app em
87
+ * `~/projetos/meu-app` sem lockfile próprio NÃO pode herdar o
88
+ * `package-lock.json` que por acaso existe em `~/projetos` — instalar lá
89
+ * mexeria num projeto que não é o do build.
90
+ */
91
+ export function ehRaizDeWorkspace(dir) {
92
+ if (existe(path.join(dir, 'pnpm-workspace.yaml')))
93
+ return true;
94
+ const pkg = lerJson(path.join(dir, 'package.json'));
95
+ if (!pkg)
96
+ return false;
97
+ const ws = pkg.workspaces;
98
+ // npm/yarn/bun aceitam `workspaces: []` OU `workspaces: { packages: [] }`.
99
+ if (Array.isArray(ws))
100
+ return true;
101
+ if (ws && typeof ws === 'object' && Array.isArray(ws.packages))
102
+ return true;
103
+ return false;
104
+ }
105
+ function lockfileDoDir(dir) {
106
+ for (const lf of LOCKFILES) {
107
+ if (existe(path.join(dir, lf.file)))
108
+ return lf;
109
+ }
110
+ return null;
111
+ }
112
+ /**
113
+ * Descobre QUAL gerenciador de pacote usar e ONDE rodar o `install`, partindo
114
+ * do diretório do app.
115
+ *
116
+ * Ordem de decisão (da mais forte pra mais fraca):
117
+ * 1. `packageManager` no package.json do próprio app (corepack) — é uma
118
+ * declaração explícita do dono do projeto;
119
+ * 2. lockfile NO PRÓPRIO diretório do app (repo de app único);
120
+ * 3. subindo a árvore: o primeiro ancestral que tem lockfile **e** se declara
121
+ * raiz de workspace (`pnpm-workspace.yaml` ou `workspaces` no package.json).
122
+ * O `packageManager` desse ancestral, se houver, vence o lockfile dele;
123
+ * 4. nada encontrado → `npm` no próprio diretório do app (comportamento
124
+ * histórico — não quebra ninguém que já usava o CLI).
125
+ *
126
+ * A subida PARA no diretório que contém `.git` (inclusive): fora do repo não
127
+ * existe workspace que interesse a este build.
128
+ */
129
+ export function detectPackageManager(appDir) {
130
+ const campoLocal = parseCampoPackageManager(lerJson(path.join(appDir, 'package.json'))?.packageManager);
131
+ const lockLocal = lockfileDoDir(appDir);
132
+ // O campo local é a declaração mais explícita que existe — mas o `rootDir`
133
+ // ainda pode ser um ancestral (app de monorepo que declara `packageManager`
134
+ // e deixa o lockfile na raiz). Por isso o rootDir é resolvido à parte.
135
+ if (lockLocal) {
136
+ return {
137
+ name: campoLocal ?? lockLocal.name,
138
+ rootDir: appDir,
139
+ source: campoLocal ? 'campo packageManager' : 'lockfile',
140
+ lockfile: campoLocal ? undefined : lockLocal.file,
141
+ };
142
+ }
143
+ let dir = appDir;
144
+ for (let i = 0; i < MAX_SUBIDA; i++) {
145
+ const temGit = existe(path.join(dir, '.git'));
146
+ const pai = path.dirname(dir);
147
+ if (temGit || pai === dir)
148
+ break;
149
+ dir = pai;
150
+ const lock = lockfileDoDir(dir);
151
+ if (!lock) {
152
+ if (existe(path.join(dir, '.git')))
153
+ break;
154
+ continue;
155
+ }
156
+ // Lockfile de ancestral só vale se o ancestral É raiz de workspace — ver
157
+ // `ehRaizDeWorkspace` pro porquê (não sequestrar projeto vizinho).
158
+ if (!ehRaizDeWorkspace(dir))
159
+ break;
160
+ const campoRaiz = parseCampoPackageManager(lerJson(path.join(dir, 'package.json'))?.packageManager);
161
+ return {
162
+ name: campoLocal ?? campoRaiz ?? lock.name,
163
+ rootDir: dir,
164
+ source: campoLocal || campoRaiz ? 'campo packageManager' : 'lockfile',
165
+ lockfile: campoLocal || campoRaiz ? undefined : lock.file,
166
+ };
167
+ }
168
+ return {
169
+ name: campoLocal ?? 'npm',
170
+ rootDir: appDir,
171
+ source: campoLocal ? 'campo packageManager' : 'default',
172
+ };
173
+ }
174
+ /**
175
+ * `install` NÃO-DESTRUTIVO por gerenciador.
176
+ *
177
+ * bug_93f984a já tinha estabelecido a regra pro npm: nunca `npm ci` (apaga
178
+ * node_modules e briga com os file locks do `next dev` no Windows). A mesma
179
+ * regra vale pros outros — nada de `--frozen-lockfile` nem `--immutable`, que
180
+ * falham de cara quando o dev acabou de mexer num package.json do workspace.
181
+ */
182
+ export function comandoInstall(pm) {
183
+ switch (pm) {
184
+ case 'pnpm':
185
+ return { cmd: 'pnpm', args: ['install', '--no-frozen-lockfile'] };
186
+ case 'yarn':
187
+ // Serve pro yarn classic (1.x) e pro berry — ambos aceitam `install` puro.
188
+ return { cmd: 'yarn', args: ['install'] };
189
+ case 'bun':
190
+ return { cmd: 'bun', args: ['install'] };
191
+ case 'npm':
192
+ default:
193
+ return { cmd: 'npm', args: ['install', '--no-save', '--no-audit', '--no-fund'] };
194
+ }
195
+ }
196
+ /** Roda um script do package.json (`build`, `start`, …). */
197
+ export function comandoRunScript(pm, script) {
198
+ switch (pm) {
199
+ case 'pnpm':
200
+ return { cmd: 'pnpm', args: ['run', script] };
201
+ case 'yarn':
202
+ return { cmd: 'yarn', args: ['run', script] };
203
+ case 'bun':
204
+ return { cmd: 'bun', args: ['run', script] };
205
+ case 'npm':
206
+ default:
207
+ return { cmd: 'npm', args: ['run', script] };
208
+ }
209
+ }
210
+ /**
211
+ * Executa um binário de `node_modules/.bin` (`next`, `vite`, `tsc`…).
212
+ *
213
+ * Usado só no caminho Windows do bug_0cf14fba/bug_893891f, onde o CLI desmonta
214
+ * o prefixo de env estilo Unix do script e roda o comando real direto. Com pnpm
215
+ * o `npx` NÃO serve: os binários ficam atrás do store de links do pnpm e o npx
216
+ * acabaria BAIXANDO o pacote do registry em vez de usar o local.
217
+ */
218
+ export function comandoExecBin(pm, bin, args) {
219
+ switch (pm) {
220
+ case 'pnpm':
221
+ return { cmd: 'pnpm', args: ['exec', bin, ...args] };
222
+ case 'yarn':
223
+ return { cmd: 'yarn', args: ['exec', bin, ...args] };
224
+ case 'bun':
225
+ return { cmd: 'bunx', args: [bin, ...args] };
226
+ case 'npm':
227
+ default:
228
+ return { cmd: 'npx', args: [bin, ...args] };
229
+ }
230
+ }
231
+ /** Profundidade máxima de varredura dentro do standalone à procura do server.js. */
232
+ const MAX_PROFUNDIDADE_STANDALONE = 6;
233
+ /**
234
+ * Acha ONDE o `server.js` do Next.js ficou dentro de `.next/standalone`.
235
+ *
236
+ * Em repo de app único ele está na raiz; em monorepo o Next.js aninha o app sob
237
+ * o caminho dele relativo ao `outputFileTracingRoot` (`apps/web/server.js`).
238
+ * Não dá pra deduzir esse prefixo do `next.config` (o `outputFileTracingRoot`
239
+ * pode ser implícito, vindo da detecção de workspace do próprio Next.js), então
240
+ * a verdade é a árvore PÓS-BUILD — a mesma lógica do `isStandaloneBuildDir`.
241
+ *
242
+ * Varredura em largura, pulando `node_modules` (pacote dependente pode ter um
243
+ * `server.js` qualquer e envenenar a busca). Entre candidatos, ganha o que
244
+ * TAMBÉM tem um diretório `.next` ao lado — é o par que o Next.js sempre emite
245
+ * junto (`server.js` + `.next/` com os chunks de servidor). Empate real resolve
246
+ * pelo mais raso e, em seguida, por ordem alfabética (determinismo: dois builds
247
+ * da mesma árvore têm que dar o mesmo tarball).
248
+ *
249
+ * Devolve `null` quando não há standalone nenhum (build não-standalone) ou
250
+ * quando há standalone mas nenhum `server.js` — nesse segundo caso quem chama
251
+ * precisa FALHAR, nunca empacotar um tarball sem entrypoint.
252
+ */
253
+ export function resolveStandaloneLayout(appDir) {
254
+ const standaloneDir = path.join(appDir, '.next', 'standalone');
255
+ try {
256
+ if (!fs.statSync(standaloneDir).isDirectory())
257
+ return null;
258
+ }
259
+ catch {
260
+ return null;
261
+ }
262
+ const candidatos = [];
263
+ const fila = [
264
+ { dir: standaloneDir, prefix: '', profundidade: 0 },
265
+ ];
266
+ while (fila.length > 0) {
267
+ const atual = fila.shift();
268
+ let entradas;
269
+ try {
270
+ entradas = fs.readdirSync(atual.dir, { withFileTypes: true });
271
+ }
272
+ catch {
273
+ continue;
274
+ }
275
+ const temServer = entradas.some((e) => e.name === 'server.js' && e.isFile());
276
+ if (temServer) {
277
+ candidatos.push({
278
+ prefix: atual.prefix,
279
+ temNext: entradas.some((e) => e.name === '.next' && e.isDirectory()),
280
+ profundidade: atual.profundidade,
281
+ });
282
+ // Não desce mais por este ramo: achado o app, o que houver abaixo é
283
+ // output dele, não outro app.
284
+ continue;
285
+ }
286
+ if (atual.profundidade >= MAX_PROFUNDIDADE_STANDALONE)
287
+ continue;
288
+ for (const e of entradas) {
289
+ if (!e.isDirectory())
290
+ continue;
291
+ // `node_modules` nunca hospeda o app; `.next` abaixo da raiz é output.
292
+ if (e.name === 'node_modules' || e.name === '.next')
293
+ continue;
294
+ fila.push({
295
+ dir: path.join(atual.dir, e.name),
296
+ prefix: atual.prefix ? `${atual.prefix}/${e.name}` : e.name,
297
+ profundidade: atual.profundidade + 1,
298
+ });
299
+ }
300
+ }
301
+ if (candidatos.length === 0)
302
+ return null;
303
+ candidatos.sort((a, b) => {
304
+ if (a.temNext !== b.temNext)
305
+ return a.temNext ? -1 : 1;
306
+ if (a.profundidade !== b.profundidade)
307
+ return a.profundidade - b.profundidade;
308
+ return a.prefix.localeCompare(b.prefix);
309
+ });
310
+ const vencedor = candidatos[0];
311
+ return {
312
+ standaloneDir,
313
+ appPrefix: vencedor.prefix,
314
+ entrypoint: vencedor.prefix ? `${vencedor.prefix}/server.js` : 'server.js',
315
+ };
316
+ }
317
+ /**
318
+ * Resolve o `-C` do `tar` que faz `.next/static` e `public` caírem DENTRO do
319
+ * prefixo do app no tarball.
320
+ *
321
+ * O Next.js não copia nenhum dos dois pro standalone (limitação conhecida), e o
322
+ * runtime os procura ao lado do `server.js` — ou seja, dentro do prefixo do app,
323
+ * não na raiz do tar. Era exatamente isso que saía errado em monorepo
324
+ * (bug_678ddc98): o tar levava `./.next/static` e `./public` na raiz enquanto o
325
+ * server rodava de `apps/web/`, e o app subia sem CSS/JS e sem os estáticos.
326
+ *
327
+ * O truque pra gravar o membro já aninhado SEM `--transform` (GNU) nem `-s`
328
+ * (bsdtar), que não são portáveis entre os dois tars: o `appPrefix` é, por
329
+ * construção, `path.relative(outputFileTracingRoot, appDir)` — então o mesmo
330
+ * caminho EXISTE no disco a partir da raiz de tracing. Basta dar `-C <raiz de
331
+ * tracing>` e pedir o membro `apps/web/.next/static`, que o tar grava com o
332
+ * caminho completo.
333
+ *
334
+ * Devolve `null` quando o prefixo não casa com o disco (não deveria acontecer —
335
+ * é a trava contra empacotar caminho inventado).
336
+ */
337
+ export function baseDeInjecaoNoTar(appDir, appPrefix) {
338
+ if (!appPrefix)
339
+ return { chdir: appDir, prefixo: '' };
340
+ const niveis = appPrefix.split('/').filter(Boolean);
341
+ const chdir = path.resolve(appDir, ...niveis.map(() => '..'));
342
+ // A igualdade é a prova de que `<chdir>/<appPrefix>` é o MESMO diretório que
343
+ // `appDir` — sem isso o tar gravaria um caminho que não existe.
344
+ if (path.resolve(chdir, ...niveis) !== path.resolve(appDir))
345
+ return null;
346
+ return { chdir, prefixo: `${appPrefix}/` };
347
+ }
348
+ //# sourceMappingURL=build-targets.js.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Saída do processo a partir de um `NeetruCliError` (bug_89d2497e, etapa 3).
3
+ *
4
+ * O cli-kit monta o erro (puro); aqui ele é impresso — JSON no stdout em
5
+ * `--json`, texto humano no stderr fora dele — e o processo sai com o código
6
+ * de saída DO ERRO. Ponto único: `handleApiError`, `resolveStepUp`, a validação
7
+ * de `--env` e o trap global de `index.ts` passam por aqui.
8
+ */
9
+ import { NeetruCliError } from '../cli-kit/errors.js';
10
+ /** Imprime o erro e devolve o código de saída — sem encerrar. */
11
+ export declare function emitCliError(error: NeetruCliError, json?: boolean): number;
12
+ /** Imprime o erro e encerra com o código de saída dele. Nunca retorna. */
13
+ export declare function exitWithCliError(error: NeetruCliError, json?: boolean): never;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Saída do processo a partir de um `NeetruCliError` (bug_89d2497e, etapa 3).
3
+ *
4
+ * O cli-kit monta o erro (puro); aqui ele é impresso — JSON no stdout em
5
+ * `--json`, texto humano no stderr fora dele — e o processo sai com o código
6
+ * de saída DO ERRO. Ponto único: `handleApiError`, `resolveStepUp`, a validação
7
+ * de `--env` e o trap global de `index.ts` passam por aqui.
8
+ */
9
+ import { renderCliError } from '../cli-kit/errors.js';
10
+ import { log } from '../utils/logger.js';
11
+ import { safeExit } from '../utils/safe-exit.js';
12
+ /** Imprime o erro e devolve o código de saída — sem encerrar. */
13
+ export function emitCliError(error, json) {
14
+ if (json)
15
+ console.log(JSON.stringify(error.toJSON()));
16
+ else
17
+ log.error(renderCliError(error));
18
+ return error.exit;
19
+ }
20
+ /** Imprime o erro e encerra com o código de saída dele. Nunca retorna. */
21
+ export function exitWithCliError(error, json) {
22
+ return safeExit(emitCliError(error, json));
23
+ }
24
+ //# sourceMappingURL=cli-error.js.map
@@ -18,6 +18,27 @@ export declare function saveMfaSession(mfaSessionToken: string, expiresAt: strin
18
18
  * apagado junto com o Bearer token.
19
19
  */
20
20
  export declare function clearMfaSession(): Promise<void>;
21
+ /**
22
+ * uid dono de um token de sessão MFA. O Core emite
23
+ * `<uid_base64url>.<issuedAt_hex>.<hmac_sha256_hex>` (`createCliMfaSessionToken`
24
+ * em `src/lib/auth-mfa-session.ts`): o uid é a parte ASSINADA, não segredo — o
25
+ * servidor só aceita a sessão se ele bater com o uid do Bearer. `null` se o
26
+ * formato não for reconhecido.
27
+ */
28
+ export declare function mfaSessionOwnerUid(token: string): string | null;
29
+ /**
30
+ * Descarta a sessão MFA salva quando ela não é do `uid` que acabou de logar.
31
+ *
32
+ * A8 (2026-10-13): `neetru login` com outra conta trocava o Bearer mas deixava
33
+ * o `mfa-session.json` da conta anterior. O Core recusa sessão de outro uid,
34
+ * então TODO comando destrutivo tomava 401 `mfa_required` por até 1h (e, antes
35
+ * do conserto da precedência em `resolveStepUp`, nem `--mfa-token` salvava).
36
+ * Sessão de dono desconhecido (arquivo corrompido, formato não reconhecido)
37
+ * também sai — o servidor recusaria do mesmo jeito. Sessão do MESMO uid fica
38
+ * (re-login na mesma conta não deve exigir TOTP de novo). Retorna `true` se
39
+ * apagou.
40
+ */
41
+ export declare function discardMfaSessionOfOtherUid(uid: string): Promise<boolean>;
21
42
  export interface ConfirmOptions {
22
43
  /** `--yes` / `--force` — pula a confirmação (modo script/CI). */
23
44
  yes?: boolean;
@@ -25,6 +46,17 @@ export interface ConfirmOptions {
25
46
  /** Saída em JSON — não imprime prompt humano. */
26
47
  json?: boolean;
27
48
  }
49
+ /**
50
+ * O que dizer quando a confirmação não pode ser perguntada (P105 /
51
+ * bug_89d2497e). Cita só as flags de confirmação que o comando EM EXECUÇÃO
52
+ * declara: o texto fixo "use --yes (ou --force)" chegava a 8 comandos que
53
+ * declaram `--yes` mas não `--force` (medido na árvore do Commander em
54
+ * 2026-10-18: `servers pgbouncer sync-userlist`, `products memory set`,
55
+ * `vm memory set`, `db move start|abort|decommission`, `promote execute`,
56
+ * `mobile revoke`) — quem seguisse com `--force` tomava "unknown option".
57
+ * Sem nenhuma das duas (ou fora do Commander, como no menu), não cita flag.
58
+ */
59
+ export declare function confirmationAdvice(modo: 'json' | 'nao-interativo'): string;
28
60
  /**
29
61
  * Gate de confirmação pra operações DESTRUTIVAS (suspend, deactivate, delete,
30
62
  * rollback, archive, yank). Se `--yes`/`--force` foi passado, retorna sem
@@ -58,19 +90,21 @@ export interface StepUpOptions extends ConfirmOptions {
58
90
  }
59
91
  /**
60
92
  * Resolve o que uma operação destrutiva TOP-TIER precisa mandar pro servidor:
61
- * - `headers`: `X-Neetru-MFA-Session` (sessão de 1h) OU `X-Neetru-MFA-Token`
62
- * (TOTP fresco) e/ou `X-Neetru-Dry-Run`.
93
+ * - `headers`: `X-Neetru-MFA-Token` (TOTP fresco) OU `X-Neetru-MFA-Session`
94
+ * (sessão de 1h) e/ou `X-Neetru-Dry-Run`.
63
95
  *
64
96
  * Ordem de preferência:
65
97
  * 1. dry-run: sem MFA, só `X-Neetru-Dry-Run: true`.
66
- * 2. Sessão de 1h salva localmente (`~/.config/neetru-cli/mfa-session.json`):
67
- * usa `X-Neetru-MFA-Session` sem pedir TOTP. Silencioso — o operador
68
- * não precisa saber que a sessão está ativa.
69
- * 3. TOTP fresco: do flag `--mfa-token` ou prompt interativo.
70
- * Em terminal não-interativo sem `--mfa-token`, encerra com instrução
71
- * clara — o servidor recusaria de qualquer forma (fail-closed).
98
+ * 2. `--mfa-token` explícito: manda `X-Neetru-MFA-Token` — e também a sessão
99
+ * salva, se houver (o Core tenta a sessão antes e não gasta o TOTP à toa).
100
+ * O código NUNCA é descartado em favor da sessão (A8).
101
+ * 3. Sessão de 1h salva localmente: usa `X-Neetru-MFA-Session` sem pedir
102
+ * TOTP. Silencioso — o operador não precisa saber que a sessão está ativa.
103
+ * 4. Prompt interativo do TOTP. Em `--json`/não-interativo sem código nem
104
+ * sessão, encerra com instrução clara — o servidor recusaria de qualquer
105
+ * forma (fail-closed).
72
106
  *
73
- * feature mfa-session (2026-06-12): o item 2 elimina o re-prompt TOTP a cada
107
+ * feature mfa-session (2026-06-12): o item 3 elimina o re-prompt TOTP a cada
74
108
  * comando destrutivo quando o operador já rodou `neetru auth mfa-session`.
75
109
  */
76
110
  export declare function resolveStepUp(opts: StepUpOptions): Promise<{