@neetru/cli 2.29.0 → 2.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (259) hide show
  1. package/CHANGELOG.md +141 -0
  2. package/README.md +63 -17
  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 +114 -2
  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 +17 -24
  26. package/dist/commands/deploy.d.ts +136 -2
  27. package/dist/commands/deploy.js +547 -69
  28. package/dist/commands/deployments.js +11 -6
  29. package/dist/commands/dev-context.js +15 -5
  30. package/dist/commands/dev-up.d.ts +7 -5
  31. package/dist/commands/dev-up.js +24 -23
  32. package/dist/commands/docs-produto.d.ts +90 -0
  33. package/dist/commands/docs-produto.js +384 -0
  34. package/dist/commands/doctor.js +36 -1
  35. package/dist/commands/domains.js +85 -4
  36. package/dist/commands/env.d.ts +9 -3
  37. package/dist/commands/env.js +23 -3
  38. package/dist/commands/infra-read.js +2 -2
  39. package/dist/commands/init.d.ts +2 -0
  40. package/dist/commands/init.js +14 -1
  41. package/dist/commands/login.js +35 -8
  42. package/dist/commands/logs.js +12 -4
  43. package/dist/commands/mobile.js +33 -9
  44. package/dist/commands/new.d.ts +31 -1
  45. package/dist/commands/new.js +94 -4
  46. package/dist/commands/open.js +16 -6
  47. package/dist/commands/ops.js +1 -1
  48. package/dist/commands/products-db.d.ts +1 -0
  49. package/dist/commands/products-db.js +41 -8
  50. package/dist/commands/products.d.ts +17 -3
  51. package/dist/commands/products.js +84 -16
  52. package/dist/commands/promote.js +30 -5
  53. package/dist/commands/secrets.d.ts +91 -0
  54. package/dist/commands/secrets.js +471 -0
  55. package/dist/commands/servers.js +6 -4
  56. package/dist/commands/status.js +2 -2
  57. package/dist/commands/support.js +5 -3
  58. package/dist/commands/tenants.js +28 -16
  59. package/dist/commands/upgrade.d.ts +9 -0
  60. package/dist/commands/upgrade.js +50 -1
  61. package/dist/commands/vm-memory.js +1 -0
  62. package/dist/commands/webhooks.d.ts +2 -0
  63. package/dist/commands/webhooks.js +9 -3
  64. package/dist/commands/workspaces.js +42 -11
  65. package/dist/index.js +142 -20
  66. package/dist/lib/api-client.d.ts +22 -1
  67. package/dist/lib/api-client.js +79 -8
  68. package/dist/lib/api-error.d.ts +14 -0
  69. package/dist/lib/api-error.js +107 -46
  70. package/dist/lib/build-targets.d.ts +127 -0
  71. package/dist/lib/build-targets.js +348 -0
  72. package/dist/lib/cli-error.d.ts +13 -0
  73. package/dist/lib/cli-error.js +24 -0
  74. package/dist/lib/cli-write.d.ts +43 -9
  75. package/dist/lib/cli-write.js +154 -45
  76. package/dist/lib/compose-generator.d.ts +13 -9
  77. package/dist/lib/compose-generator.js +28 -60
  78. package/dist/lib/config-schema.d.ts +36 -2
  79. package/dist/lib/config-schema.js +11 -0
  80. package/dist/lib/db-local/db-json.d.ts +1 -1
  81. package/dist/lib/db-local/db-json.js +13 -5
  82. package/dist/lib/db-local/env.d.ts +15 -3
  83. package/dist/lib/db-local/env.js +37 -10
  84. package/dist/lib/db-pipeline/build-deps.d.ts +5 -1
  85. package/dist/lib/db-pipeline/build-deps.js +23 -3
  86. package/dist/lib/db-pipeline/types.d.ts +6 -2
  87. package/dist/lib/db-pipeline/types.js +0 -18
  88. package/dist/lib/deploy-target-contract.d.ts +152 -0
  89. package/dist/lib/deploy-target-contract.js +411 -0
  90. package/dist/lib/env-file-do-build.d.ts +19 -0
  91. package/dist/lib/env-file-do-build.js +44 -0
  92. package/dist/lib/envs.d.ts +108 -0
  93. package/dist/lib/envs.js +127 -0
  94. package/dist/lib/fs-seguro.d.ts +63 -0
  95. package/dist/lib/fs-seguro.js +108 -0
  96. package/dist/lib/mobile-local/mobile-json.js +10 -4
  97. package/dist/lib/pickers.d.ts +44 -7
  98. package/dist/lib/pickers.js +60 -4
  99. package/dist/lib/product-docs/check.d.ts +62 -0
  100. package/dist/lib/product-docs/check.js +489 -0
  101. package/dist/lib/product-docs/config.d.ts +66 -0
  102. package/dist/lib/product-docs/config.js +234 -0
  103. package/dist/lib/product-docs/dates.d.ts +17 -0
  104. package/dist/lib/product-docs/dates.js +41 -0
  105. package/dist/lib/product-docs/frontmatter.d.ts +43 -0
  106. package/dist/lib/product-docs/frontmatter.js +302 -0
  107. package/dist/lib/product-docs/git.d.ts +16 -0
  108. package/dist/lib/product-docs/git.js +92 -0
  109. package/dist/lib/product-docs/markdown.d.ts +27 -0
  110. package/dist/lib/product-docs/markdown.js +98 -0
  111. package/dist/lib/product-docs/ops.d.ts +133 -0
  112. package/dist/lib/product-docs/ops.js +975 -0
  113. package/dist/lib/product-docs/structure.d.ts +61 -0
  114. package/dist/lib/product-docs/structure.js +239 -0
  115. package/dist/lib/product-docs/sync.d.ts +107 -0
  116. package/dist/lib/product-docs/sync.js +322 -0
  117. package/dist/lib/product-docs/taxonomy.d.ts +46 -0
  118. package/dist/lib/product-docs/taxonomy.js +163 -0
  119. package/dist/lib/product-docs/templates.d.ts +53 -0
  120. package/dist/lib/product-docs/templates.js +245 -0
  121. package/dist/lib/public-secret-scan.d.ts +117 -0
  122. package/dist/lib/public-secret-scan.js +771 -0
  123. package/dist/lib/render.d.ts +16 -0
  124. package/dist/lib/render.js +34 -4
  125. package/dist/lib/segredo-produto.d.ts +124 -0
  126. package/dist/lib/segredo-produto.js +336 -0
  127. package/dist/lib/texto-utf8.d.ts +96 -0
  128. package/dist/lib/texto-utf8.js +196 -0
  129. package/package.json +2 -1
  130. package/dist/cli-kit/format.js.map +0 -1
  131. package/dist/cli-kit/glyphs.js.map +0 -1
  132. package/dist/cli-kit/index.js.map +0 -1
  133. package/dist/cli-kit/palette.js.map +0 -1
  134. package/dist/commands/add.js.map +0 -1
  135. package/dist/commands/admin/iam-check.js.map +0 -1
  136. package/dist/commands/admin/oidc-login.js.map +0 -1
  137. package/dist/commands/admin/sdk-credential.js.map +0 -1
  138. package/dist/commands/agent-release.js.map +0 -1
  139. package/dist/commands/agent-write.js.map +0 -1
  140. package/dist/commands/ai-models.js.map +0 -1
  141. package/dist/commands/ai.js.map +0 -1
  142. package/dist/commands/api-catalog.js.map +0 -1
  143. package/dist/commands/archive.js.map +0 -1
  144. package/dist/commands/artifact-registry.js.map +0 -1
  145. package/dist/commands/audit.js.map +0 -1
  146. package/dist/commands/auth.js.map +0 -1
  147. package/dist/commands/autocomplete.js.map +0 -1
  148. package/dist/commands/billing.js.map +0 -1
  149. package/dist/commands/bootstrap.js.map +0 -1
  150. package/dist/commands/bug.js.map +0 -1
  151. package/dist/commands/build.js.map +0 -1
  152. package/dist/commands/chat-menu.js.map +0 -1
  153. package/dist/commands/chat.js.map +0 -1
  154. package/dist/commands/cloud-run.js.map +0 -1
  155. package/dist/commands/code.js.map +0 -1
  156. package/dist/commands/config.js.map +0 -1
  157. package/dist/commands/customers.js.map +0 -1
  158. package/dist/commands/db-move.js.map +0 -1
  159. package/dist/commands/db.js.map +0 -1
  160. package/dist/commands/deploy.js.map +0 -1
  161. package/dist/commands/deployments.js.map +0 -1
  162. package/dist/commands/dev-context.js.map +0 -1
  163. package/dist/commands/dev-up.js.map +0 -1
  164. package/dist/commands/dev.js.map +0 -1
  165. package/dist/commands/docs.js.map +0 -1
  166. package/dist/commands/doctor.js.map +0 -1
  167. package/dist/commands/domains.js.map +0 -1
  168. package/dist/commands/dr.js.map +0 -1
  169. package/dist/commands/env.js.map +0 -1
  170. package/dist/commands/hosting-write.js.map +0 -1
  171. package/dist/commands/infra-read.js.map +0 -1
  172. package/dist/commands/init.js.map +0 -1
  173. package/dist/commands/login.js.map +0 -1
  174. package/dist/commands/logout.js.map +0 -1
  175. package/dist/commands/logs.js.map +0 -1
  176. package/dist/commands/mobile.js.map +0 -1
  177. package/dist/commands/mocks.js.map +0 -1
  178. package/dist/commands/new.js.map +0 -1
  179. package/dist/commands/open.js.map +0 -1
  180. package/dist/commands/ops.js.map +0 -1
  181. package/dist/commands/products-db.js.map +0 -1
  182. package/dist/commands/products.js.map +0 -1
  183. package/dist/commands/promote.js.map +0 -1
  184. package/dist/commands/publish.js.map +0 -1
  185. package/dist/commands/schema.js.map +0 -1
  186. package/dist/commands/servers.js.map +0 -1
  187. package/dist/commands/smoke.js.map +0 -1
  188. package/dist/commands/status.js.map +0 -1
  189. package/dist/commands/support.js.map +0 -1
  190. package/dist/commands/surface-status.js.map +0 -1
  191. package/dist/commands/tenants.js.map +0 -1
  192. package/dist/commands/ui.js.map +0 -1
  193. package/dist/commands/upgrade.js.map +0 -1
  194. package/dist/commands/validate.js.map +0 -1
  195. package/dist/commands/vm-memory.js.map +0 -1
  196. package/dist/commands/vm.js.map +0 -1
  197. package/dist/commands/webhooks.js.map +0 -1
  198. package/dist/commands/whoami.js.map +0 -1
  199. package/dist/commands/workspaces.js.map +0 -1
  200. package/dist/index.js.map +0 -1
  201. package/dist/lib/agent-artifact-url.js.map +0 -1
  202. package/dist/lib/agent-commands.js.map +0 -1
  203. package/dist/lib/ai/auth-discovery.js.map +0 -1
  204. package/dist/lib/ai/context.js.map +0 -1
  205. package/dist/lib/ai/orchestrator.js.map +0 -1
  206. package/dist/lib/api-client.js.map +0 -1
  207. package/dist/lib/api-error.js.map +0 -1
  208. package/dist/lib/auth.js.map +0 -1
  209. package/dist/lib/cli-read.js.map +0 -1
  210. package/dist/lib/cli-write.js.map +0 -1
  211. package/dist/lib/code-agent-budget.js.map +0 -1
  212. package/dist/lib/code-agent-files.js.map +0 -1
  213. package/dist/lib/code-agent-gateway.js.map +0 -1
  214. package/dist/lib/code-agent-git-tools.js.map +0 -1
  215. package/dist/lib/code-agent-protocol.js.map +0 -1
  216. package/dist/lib/code-agent-session.js.map +0 -1
  217. package/dist/lib/code-agent-settings.js.map +0 -1
  218. package/dist/lib/code-agent-skills.js.map +0 -1
  219. package/dist/lib/code-agent-subagents.js.map +0 -1
  220. package/dist/lib/code-agent-tools.js.map +0 -1
  221. package/dist/lib/code-agent-tui.js.map +0 -1
  222. package/dist/lib/code-agent-types.js.map +0 -1
  223. package/dist/lib/code-agent-ui.js.map +0 -1
  224. package/dist/lib/code-agent-web-tools.js.map +0 -1
  225. package/dist/lib/code-agent-write-tools.js.map +0 -1
  226. package/dist/lib/compose-generator.js.map +0 -1
  227. package/dist/lib/config-schema.js.map +0 -1
  228. package/dist/lib/config.js.map +0 -1
  229. package/dist/lib/db-local/db-json.js.map +0 -1
  230. package/dist/lib/db-local/env.js.map +0 -1
  231. package/dist/lib/db-local/fingerprint.js.map +0 -1
  232. package/dist/lib/db-local/index.js.map +0 -1
  233. package/dist/lib/db-pipeline/build-deps.js.map +0 -1
  234. package/dist/lib/db-pipeline/errors.js.map +0 -1
  235. package/dist/lib/db-pipeline/index.js.map +0 -1
  236. package/dist/lib/db-pipeline/pipeline.js.map +0 -1
  237. package/dist/lib/db-pipeline/rehearse.js.map +0 -1
  238. package/dist/lib/db-pipeline/types.js.map +0 -1
  239. package/dist/lib/dev-local-context.js.map +0 -1
  240. package/dist/lib/iam-preflight.js.map +0 -1
  241. package/dist/lib/mobile-local/index.js.map +0 -1
  242. package/dist/lib/mobile-local/mobile-json.js.map +0 -1
  243. package/dist/lib/pickers.js.map +0 -1
  244. package/dist/lib/product-config.js.map +0 -1
  245. package/dist/lib/render.js.map +0 -1
  246. package/dist/lib/schema-cache.js.map +0 -1
  247. package/dist/lib/sse.js.map +0 -1
  248. package/dist/lib/telemetry.js.map +0 -1
  249. package/dist/lib/token-resolver.js.map +0 -1
  250. package/dist/lib/url-allowlist.js.map +0 -1
  251. package/dist/lib/version-check.js.map +0 -1
  252. package/dist/utils/logger.js.map +0 -1
  253. package/dist/utils/logo.js.map +0 -1
  254. package/dist/utils/safe-exit.js.map +0 -1
  255. package/dist/utils/spinner-registry.js.map +0 -1
  256. package/dist/version.js.map +0 -1
  257. package/templates/dev/Dockerfile.agent +0 -39
  258. package/templates/dev/agent-entrypoint.sh +0 -41
  259. package/templates/dev/docker-compose.dev.yml +0 -63
@@ -0,0 +1,411 @@
1
+ /**
2
+ * Contrato de compatibilidade `--target` × runtime × flags do `neetru deploy`.
3
+ *
4
+ * bug_a8375858 (o caso que motivou o módulo): um produto `runtime: nextjs`
5
+ * rodou `deploy --target workspace --artifact <tarball de 20 MB>`. A CLI leu o
6
+ * tarball como TEXTO (`readFile(…, 'utf8')`), o gzip virou ~35 MB de U+FFFD,
7
+ * subiu pro GCS como `source-*.ts`, e o Core respondeu
8
+ * **413 "Falha ao resolver a source do deploy"** — que manda o dev caçar
9
+ * TAMANHO quando o problema era TIPO DE ALVO. Dois uploads de 35 MB e meia
10
+ * hora perdida.
11
+ *
12
+ * ─── O padrão, em uma frase ─────────────────────────────────────────────────
13
+ *
14
+ * "Uma flag (ou campo do neetru.config.json) cujo significado depende do
15
+ * `--target` é aceita pela CLI, silenciosamente reinterpretada ou
16
+ * descartada, e só aparece como erro do Core DEPOIS do passo caro — ou não
17
+ * aparece nunca."
18
+ *
19
+ * Antes deste módulo o padrão era combatido um `if` por vez (bug_ec17af08
20
+ * cobriu cloud-run+`--artifact`; bug_b919e729 cobriu o espelho disso no Core),
21
+ * e cada combinação nova nascia desprotegida. Aqui ele vira UMA TABELA: cada
22
+ * alvo declara o que RECEBE, o que REJEITA (erro antes de qualquer trabalho
23
+ * caro) e o que DESCARTA (aviso — a flag some mas o deploy segue certo).
24
+ *
25
+ * ─── Regra pra classificar erro vs aviso (a que o código segue) ──────────────
26
+ *
27
+ * ERRO — a flag diz O QUE subir (pacote, URL de artefato, imagem) e o alvo
28
+ * subiria OUTRA coisa:
29
+ * · workspace sobe só um handler .ts → erro em `--artifact` com
30
+ * pacote, `--artifact-url`, `--artifact-sha256`, `--image`,
31
+ * `--registry`, `--registry-repo`;
32
+ * · cloud-run sobe só imagem → erro em `--artifact`,
33
+ * `--artifact-url`, `--artifact-sha256`.
34
+ * Nesses casos o Core também recusaria o payload (superRefine do
35
+ * `deploy-request.ts`), só que DEPOIS do build/upload caro.
36
+ * AVISO — a flag NÃO diz o que subir (servidor, porta, stack, env-file,
37
+ * domínio, build local, empacotamento local, `runtime` do config):
38
+ * ela é descartada e o deploy segue subindo a coisa certa.
39
+ *
40
+ * EXCEÇÃO REGISTRADA — vm + `--image` / `--registry` / `--registry-repo` é
41
+ * AVISO, embora a flag diga o que subir. O deploy vm sobe o tarball (o body
42
+ * nem tem campo de imagem, e o Core não recusa nada por isso), e virar erro
43
+ * quebraria script/CI que passa o mesmo conjunto de flags genéricas pra
44
+ * mais de um alvo. Decisão tomada na revisão do PR #74 (2026-10-12).
45
+ *
46
+ * O pacote que chega ao workspace por um caminho que a tabela não enxerga —
47
+ * campo `source` do neetru.config.json, ou extensão que nenhuma lista prevê —
48
+ * é recusado depois da leitura, PELO CONTEÚDO (`farejarConteudoDePacote`),
49
+ * com o mesmo código de erro. O teto de 2 MiB fica só pra handler grande.
50
+ *
51
+ * Módulo propositalmente PURO (zero fs, zero rede, zero processo) pra ser
52
+ * testável sem rodar deploy nenhum: quem lê o arquivo é o `deploy.ts`.
53
+ */
54
+ /**
55
+ * Teto ABSOLUTO da source de um deploy workspace, em bytes UTF-8.
56
+ *
57
+ * Espelha `WORKSPACE_SOURCE_MAX_BYTES` do Core
58
+ * (`src/lib/schemas/deploy-request.ts`), que o aplica nos DOIS caminhos:
59
+ * `source` inline (zod `.max()`) e `sourceUrl` baixada do GCS
60
+ * (`fetchWorkspaceSource` → `SourceFetchError(413, 'source_too_large')`).
61
+ *
62
+ * A CLI tinha só o limiar de 1.5 MiB do bug_eae4bef6, que decide *inline vs
63
+ * GCS* — e nunca o teto do Core. Resultado: tudo entre 2 MiB e infinito subia
64
+ * pro GCS e voltava como 413 opaco. Conhecer o teto aqui é o que permite
65
+ * recusar local com o número real.
66
+ */
67
+ export const WORKSPACE_SOURCE_MAX_BYTES = 2 * 1024 * 1024;
68
+ /** Bytes em KB inteiros, como as mensagens deste módulo mostram (`2048 KB`). */
69
+ function emKB(bytes) {
70
+ return `${Math.round(bytes / 1024)} KB`;
71
+ }
72
+ /**
73
+ * Extensões que identificam um PACOTE (tarball, zip, compactado), nunca um
74
+ * handler `.ts`. Só entra o que é inequívoco. A lista é a porta BARATA (nem
75
+ * lê o arquivo); a porta que não depende do nome é `farejarConteudoDePacote`.
76
+ *
77
+ * `.gz`/`.bz2`/`.xz`/`.zst` sozinhos também entram (revisão do PR #74): um
78
+ * arquivo compactado nunca é um handler, com ou sem `.tar` antes.
79
+ */
80
+ const EXTENSOES_DE_PACOTE = [
81
+ '.tar.gz',
82
+ '.tar.bz2',
83
+ '.tar.xz',
84
+ '.tar.zst',
85
+ '.tgz',
86
+ '.tbz2',
87
+ '.txz',
88
+ '.tzst',
89
+ '.tar',
90
+ '.zip',
91
+ '.gz',
92
+ '.bz2',
93
+ '.xz',
94
+ '.zst',
95
+ '.7z',
96
+ '.rar',
97
+ ];
98
+ /** `true` quando o caminho aponta um pacote de aplicação, não um handler. */
99
+ export function pareceArquivoDePacote(caminho) {
100
+ const normalizado = caminho.trim().toLowerCase().replace(/\\/g, '/');
101
+ const base = normalizado.slice(normalizado.lastIndexOf('/') + 1);
102
+ return EXTENSOES_DE_PACOTE.some((ext) => base.endsWith(ext));
103
+ }
104
+ /** Quantos bytes do começo do arquivo o farejador olha. */
105
+ export const BYTES_FAREJADOS = 8 * 1024;
106
+ /**
107
+ * Assinaturas ("magic bytes") de pacote. Uso a assinatura COMPLETA quando os
108
+ * primeiros bytes são texto imprimível (`Rar!`, `7z`, `BZh`), pra que um
109
+ * handler que por acaso comece com esse texto não seja recusado.
110
+ */
111
+ const ASSINATURAS_DE_PACOTE = [
112
+ { formato: 'gzip', bytes: [0x1f, 0x8b] },
113
+ { formato: 'zip', bytes: [0x50, 0x4b, 0x03, 0x04] },
114
+ { formato: 'zip', bytes: [0x50, 0x4b, 0x05, 0x06] }, // zip vazio
115
+ { formato: 'xz', bytes: [0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00] },
116
+ { formato: 'zstd', bytes: [0x28, 0xb5, 0x2f, 0xfd] },
117
+ { formato: '7z', bytes: [0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c] },
118
+ { formato: 'rar', bytes: [0x52, 0x61, 0x72, 0x21, 0x1a, 0x07] },
119
+ // tar sem compressão: o campo `magic` do cabeçalho, no offset 257 — POSIX
120
+ // `ustar\0` ou GNU `ustar \0`. COM o NUL de propósito (confirmação final do
121
+ // PR #74): só "ustar" casava texto comum — um comentário com "ajustar" ou
122
+ // "custar" em que `ustar` caísse no byte 257 era recusado como "arquivo tar".
123
+ // Texto nunca tem NUL; tar de verdade sempre tem.
124
+ { formato: 'tar', bytes: [0x75, 0x73, 0x74, 0x61, 0x72, 0x00], offset: 257 },
125
+ { formato: 'tar', bytes: [0x75, 0x73, 0x74, 0x61, 0x72, 0x20, 0x20, 0x00], offset: 257 },
126
+ ];
127
+ function comecaCom(bytes, assinatura, offset = 0) {
128
+ if (bytes.length < offset + assinatura.length)
129
+ return false;
130
+ return assinatura.every((b, i) => bytes[offset + i] === b);
131
+ }
132
+ /**
133
+ * bzip2: "BZh" + nível ('1'..'9') + magia de bloco (`31 41 59 26 53 59`) ou de
134
+ * fim de stream (`17 72 45 38 50 90`). Só "BZh" seria texto comum.
135
+ */
136
+ function pareceBzip2(bytes) {
137
+ if (!comecaCom(bytes, [0x42, 0x5a, 0x68]))
138
+ return false;
139
+ if (bytes.length < 10 || bytes[3] < 0x31 || bytes[3] > 0x39)
140
+ return false;
141
+ return (comecaCom(bytes, [0x31, 0x41, 0x59, 0x26, 0x53, 0x59], 4) ||
142
+ comecaCom(bytes, [0x17, 0x72, 0x45, 0x38, 0x50, 0x90], 4));
143
+ }
144
+ /** Formato do pacote cuja assinatura abre `inicio`, ou `null` se nenhuma casa. */
145
+ function formatoDePacote(inicio) {
146
+ for (const a of ASSINATURAS_DE_PACOTE) {
147
+ if (comecaCom(inicio, a.bytes, a.offset))
148
+ return a.formato;
149
+ }
150
+ if (pareceBzip2(inicio))
151
+ return 'bzip2';
152
+ return null;
153
+ }
154
+ /**
155
+ * Olha os BYTES CRUS do começo da source de um deploy workspace e diz se ela é
156
+ * pacote/binário. Devolve o motivo em PT-BR, ou `null` quando parece texto.
157
+ *
158
+ * Por que pelo conteúdo: a recusa por extensão só olhava `--artifact`. Um
159
+ * pacote apontado pelo `source` do neetru.config.json, ou com extensão que a
160
+ * lista não prevê, só batia no teto de 2 MiB. E lido como UTF-8 um binário
161
+ * incha ~1,75x (cada byte inválido vira U+FFFD, 3 bytes), então um pacote
162
+ * abaixo de ~1,15 MiB passava no teto, subia e voltava do Core como erro de
163
+ * COMPILAÇÃO do esbuild, que não diz a causa (revisão do PR #74).
164
+ *
165
+ * Tem que receber os bytes CRUS: depois de decodificado em UTF-8 o gzip já
166
+ * virou U+FFFD e a assinatura sumiu.
167
+ */
168
+ export function farejarConteudoDePacote(inicio) {
169
+ const formato = formatoDePacote(inicio);
170
+ if (formato)
171
+ return `o conteúdo tem a assinatura de um arquivo ${formato}`;
172
+ if (inicio.subarray(0, BYTES_FAREJADOS).includes(0x00)) {
173
+ return (`o conteúdo tem byte NUL nos primeiros ${emKB(BYTES_FAREJADOS)}, então é binário e ` +
174
+ 'não texto (ou foi salvo em UTF-16, e o Core só lê UTF-8)');
175
+ }
176
+ return null;
177
+ }
178
+ /** Nome da flag como o dev digita — entra nas mensagens. */
179
+ const NOME_DA_FLAG = {
180
+ artifact: '--artifact',
181
+ artifactUrl: '--artifact-url',
182
+ artifactSha256: '--artifact-sha256',
183
+ image: '--image',
184
+ registry: '--registry',
185
+ registryRepo: '--registry-repo',
186
+ buildLocal: '--build-local',
187
+ server: '--server',
188
+ port: '--port',
189
+ stack: '--stack',
190
+ envFile: '--env-file',
191
+ domain: '--domain',
192
+ localArtifact: '--local-artifact',
193
+ };
194
+ function presente(flags, k) {
195
+ const v = flags[k];
196
+ if (v === undefined || v === null)
197
+ return false;
198
+ if (typeof v === 'string')
199
+ return v.length > 0;
200
+ if (typeof v === 'boolean')
201
+ return v;
202
+ return true;
203
+ }
204
+ function listaDeFlags(flags, chaves) {
205
+ return chaves.filter((k) => presente(flags, k));
206
+ }
207
+ /**
208
+ * Texto do destino `vm` com o artefato que o dev JÁ tem na mão — a mensagem
209
+ * precisa poder ser copiada e colada, não só explicar o conceito.
210
+ */
211
+ function linhaDeComandoVm(flags) {
212
+ // Entre aspas: caminho do Windows com espaço quebrava o copia-e-cola.
213
+ if (flags.artifact)
214
+ return ` neetru deploy --target vm --artifact "${flags.artifact}"`;
215
+ if (flags.artifactUrl) {
216
+ const sha = flags.artifactSha256 ? ` --artifact-sha256 ${flags.artifactSha256}` : '';
217
+ return ` neetru deploy --target vm --artifact-url ${flags.artifactUrl}${sha}`;
218
+ }
219
+ return ' neetru deploy --target vm --artifact <tarball .tar.gz>';
220
+ }
221
+ function linhaDeComandoCloudRun(flags) {
222
+ if (flags.image)
223
+ return ` neetru deploy --target cloud-run --image ${flags.image}`;
224
+ if (flags.registry)
225
+ return ` neetru deploy --target cloud-run --registry ${flags.registry}`;
226
+ return ' neetru deploy --target cloud-run --image <uri>';
227
+ }
228
+ /**
229
+ * O que cada alvo RECEBE — frase curta reusada em várias mensagens pra que o
230
+ * dev leia a mesma definição em qualquer erro.
231
+ */
232
+ const O_QUE_O_ALVO_RECEBE = {
233
+ workspace: 'UM handler .ts (o Core compila com esbuild e roda no runtime compartilhado)',
234
+ 'cloud-run': 'UMA imagem de container OCI já buildada e pushada',
235
+ vm: 'UM tarball de aplicação já buildado (artefato + sha256 + stack)',
236
+ };
237
+ // ─── checagem ────────────────────────────────────────────────────────────────
238
+ /**
239
+ * Avalia a combinação `target × runtime × flags` ANTES de qualquer build,
240
+ * upload ou chamada ao Core.
241
+ *
242
+ * Fail-open pro desconhecido: `runtime` ausente ou fora do enum nunca bloqueia
243
+ * (repos anteriores ao campo continuam deployando). Fail-closed só no que está
244
+ * provado impossível.
245
+ */
246
+ export function checkDeployTargetContract(input) {
247
+ const { target, runtime, flags } = input;
248
+ const errors = [];
249
+ const warnings = [];
250
+ const rejeitar = (chaves, code, corpo) => {
251
+ const achadas = listaDeFlags(flags, chaves);
252
+ if (achadas.length === 0)
253
+ return;
254
+ errors.push({ code, message: corpo(achadas.map((k) => NOME_DA_FLAG[k]).join(' / ')) });
255
+ };
256
+ const avisarDescarte = (chaves) => {
257
+ for (const k of listaDeFlags(flags, chaves)) {
258
+ warnings.push(`${NOME_DA_FLAG[k]} não tem efeito em --target ${target} — a flag é descartada. ` +
259
+ `O alvo ${target} recebe ${O_QUE_O_ALVO_RECEBE[target]}.`);
260
+ }
261
+ };
262
+ if (target === 'workspace') {
263
+ // ── runtime ──────────────────────────────────────────────────────────
264
+ // Uma app Next.js não roda no workspace: o Core compila a source com
265
+ // esbuild em `platform:'browser'`, `external: []`, `format:'iife'`, teto de
266
+ // 2 MiB, e executa num `vm.Context` (`_workspace-build-helpers.ts`).
267
+ //
268
+ // Mas isto é AVISO, não erro (revisão do PR #74, 2026-10-12): `runtime` é
269
+ // OBRIGATÓRIO no config (`config-schema.ts`) e o `neetru init` grava
270
+ // `nextjs` por padrão. Erro duro aqui quebraria todo produto recém-criado
271
+ // que faz deploy de handler no workspace — e a única saída seria apagar o
272
+ // `runtime`, o que faz `validate`/`doctor`/`publish` recusarem o config. O
273
+ // caso do bug_a8375858 (pacote no workspace) continua ERRO por duas portas
274
+ // que não dependem do runtime: a extensão de `--artifact` (logo abaixo) e
275
+ // o CONTEÚDO da source, farejado depois da leitura em `runWorkspaceDeploy`
276
+ // (`farejarConteudoDePacote`), que pega também o `source` do config.
277
+ if (runtime === 'nextjs') {
278
+ warnings.push('--target workspace com runtime "nextjs": o workspace roda ' +
279
+ `${O_QUE_O_ALVO_RECEBE.workspace}, não uma aplicação Next.js com servidor, ` +
280
+ 'node_modules e estáticos. Se o que você quer subir é o app, o alvo é ' +
281
+ '`--target vm` (ou `--target cloud-run` com imagem).');
282
+ }
283
+ else if (runtime === 'node-api') {
284
+ // `neetru init --type node-api` scaffolda um servidor Fastify
285
+ // (`start: node dist/index.js`), que também não é um handler. Mas
286
+ // nada impede que um repo marcado `node-api` tenha um handler.ts de
287
+ // verdade, então aqui é AVISO: não quebra quem já deploya assim.
288
+ warnings.push('--target workspace com runtime "node-api": o workspace espera UM handler .ts, ' +
289
+ 'não o servidor Fastify que `neetru init --type node-api` scaffolda. ' +
290
+ 'Se o arquivo apontado é o entrypoint da aplicação, o alvo é `--target vm`.');
291
+ }
292
+ // ── artefato de aplicação apontado como se fosse handler ─────────────
293
+ // O erro central do bug_a8375858. Vale mesmo sem `runtime` no config.
294
+ if (flags.artifact && pareceArquivoDePacote(flags.artifact)) {
295
+ errors.push({
296
+ code: 'artifact_nao_eh_handler_workspace',
297
+ message: `--artifact "${flags.artifact}" é um pacote de aplicação, não um handler.\n` +
298
+ ' Em --target workspace a CLI lê o arquivo de --artifact como TEXTO e manda\n' +
299
+ ' o conteúdo pro Core compilar. Um pacote vira texto corrompido: se passar do\n' +
300
+ ` teto de ${emKB(WORKSPACE_SOURCE_MAX_BYTES)} do Core volta como HTTP 413\n` +
301
+ ' ("Falha ao resolver a source do deploy"); se for menor, como erro de\n' +
302
+ ' compilação. Parece problema de TAMANHO ou de código e não é: é o TIPO do alvo.\n' +
303
+ '\n' +
304
+ ' Troque o alvo:\n' +
305
+ linhaDeComandoVm(flags),
306
+ });
307
+ }
308
+ rejeitar(['artifactUrl', 'artifactSha256'], 'artefato_pre_buildado_nao_se_aplica_workspace', (nomes) => `--target workspace não usa ${nomes} (artefato pré-buildado).\n` +
309
+ ` O workspace recebe ${O_QUE_O_ALVO_RECEBE.workspace}; o Core builda a source.\n` +
310
+ '\n' +
311
+ ' Artefato pré-buildado é alvo vm:\n' +
312
+ linhaDeComandoVm(flags));
313
+ rejeitar(['image', 'registry', 'registryRepo'], 'imagem_nao_se_aplica_workspace', (nomes) => `--target workspace não usa ${nomes} (imagem de container).\n` +
314
+ ` O workspace recebe ${O_QUE_O_ALVO_RECEBE.workspace}.\n` +
315
+ '\n' +
316
+ ' Imagem de container é alvo cloud-run:\n' +
317
+ linhaDeComandoCloudRun(flags));
318
+ // `--env-file`, `--domain` e `--local-artifact` também sumiam calados aqui:
319
+ // `runWorkspaceDeploy` nunca lê nenhum dos três (revisão do PR #74).
320
+ avisarDescarte(['server', 'port', 'stack', 'buildLocal', 'envFile', 'domain', 'localArtifact']);
321
+ return { errors, warnings };
322
+ }
323
+ if (target === 'cloud-run') {
324
+ // bug_ec17af08 — mantido com o MESMO código que já estava em
325
+ // `runCloudRunDeploy`; só mudou de lugar pra haver uma tabela só. O texto
326
+ // também é o mesmo, exceto o arquivo do comando sugerido, que agora sai
327
+ // entre aspas (caminho com espaço quebrava o copia-e-cola).
328
+ // `--artifact-sha256` entrou no mesmo grupo: é par de `--artifact-url` e
329
+ // antes passava sozinho sem reclamação nenhuma.
330
+ const arquivoDoDev = flags.artifact ?? flags.artifactUrl;
331
+ rejeitar(['artifact', 'artifactUrl', 'artifactSha256'], 'artifact_not_supported_cloud_run', (nomes) => `target=cloud-run não aceita ${nomes} (tarball source).\n` +
332
+ ' Cloud Run precisa de uma imagem de container OCI já buildada e pushada.\n' +
333
+ '\n' +
334
+ ' Opções:\n' +
335
+ ' 1. --image <uri> — URI de imagem já no Artifact Registry.\n' +
336
+ ' Exemplo: --image=us-central1-docker.pkg.dev/neetru/gestovendas-staging/app:1.0.0\n' +
337
+ '\n' +
338
+ ' 2. --registry <host|host/project/repo> — CLI usa Cloud Build remoto automaticamente.\n' +
339
+ ' Não exige Docker instalado. Requer gcloud autenticado.\n' +
340
+ ' Exemplo: --registry=us-central1-docker.pkg.dev/neetru/gestovendas-staging\n' +
341
+ '\n' +
342
+ ' 3. Mude o target pra vm ou workspace se quiser usar o tarball:\n' +
343
+ ` --target=vm --artifact=${arquivoDoDev ? `"${arquivoDoDev}"` : '<file>'}`);
344
+ // O Core recusa `serverId` em cloud-run (`deploy-request.ts` superRefine),
345
+ // mas a CLI nem chega a mandar — `pickServer` só roda em target=vm. Ou
346
+ // seja: hoje a flag some calada. Aviso, não erro.
347
+ // `--domain` e `--local-artifact` só existem em vm (revisão do PR #74).
348
+ avisarDescarte(['server', 'domain', 'localArtifact']);
349
+ return { errors, warnings };
350
+ }
351
+ // target === 'vm'
352
+ // `--image`/`--registry`/`--registry-repo`/`--build-local` são de cloud-run e
353
+ // em vm somem sem dizer nada: o body do deploy vm nem tem campo pra eles, e o
354
+ // schema do Core (sem `.strict()`) descartaria em silêncio de qualquer jeito.
355
+ // `--image`/`--registry`/`--registry-repo` são a EXCEÇÃO REGISTRADA no
356
+ // cabeçalho: nomeiam o que subir e mesmo assim ficam como aviso, porque o
357
+ // deploy vm sobe o tarball e erro aqui quebraria script com flags genéricas.
358
+ //
359
+ // `--port` fica de fora de propósito: `runDeploy` já emite o aviso dele
360
+ // (P6/bug_6d92ef71, com texto específico sobre alocação de porta pelo Core).
361
+ avisarDescarte(['image', 'registry', 'registryRepo', 'buildLocal']);
362
+ return { errors, warnings };
363
+ }
364
+ const DE_ONDE_VEIO = {
365
+ artifact: 'apontado por --artifact',
366
+ config: 'apontado pelo campo "source" do neetru.config.json',
367
+ padrao: 'achado na busca padrão do handler (sem --artifact e sem "source" no config)',
368
+ };
369
+ /**
370
+ * Mensagem da recusa de uma source de workspace que é pacote, achada pelo nome
371
+ * ou pelo conteúdo DEPOIS da leitura. Usa o mesmo código de erro da recusa por
372
+ * `--artifact` (`artifact_nao_eh_handler_workspace`): é o mesmo erro, achado
373
+ * por outra porta.
374
+ */
375
+ export function mensagemSourceNaoEhHandler(relPath, motivo, origem) {
376
+ return (`"${relPath}" não é um handler .ts: ${motivo}.\n` +
377
+ ` (${DE_ONDE_VEIO[origem]})\n` +
378
+ '\n' +
379
+ ' Em --target workspace a CLI lê a source como TEXTO e manda pro Core compilar.\n' +
380
+ ' Um pacote vira texto corrompido e volta como erro de compilação (ou HTTP 413)\n' +
381
+ ' que não diz a causa. Nada foi enviado.\n' +
382
+ '\n' +
383
+ ` Se é o pacote da aplicação, o alvo certo é vm (que recebe ${O_QUE_O_ALVO_RECEBE.vm}):\n` +
384
+ ` neetru deploy --target vm --artifact "${relPath}"\n` +
385
+ (origem === 'config'
386
+ ? ' Se o handler é outro arquivo, corrija o "source" do neetru.config.json.\n'
387
+ : ''));
388
+ }
389
+ /**
390
+ * Mensagem do estouro do teto de source do workspace, usada depois que a
391
+ * source já foi lida e o farejador de pacote não a recusou: na prática, um
392
+ * handler que ficou grande demais.
393
+ *
394
+ * Diz o número real, o teto real, e o alvo certo — em vez do 413 do Core, que
395
+ * diz só "Falha ao resolver a source do deploy".
396
+ */
397
+ export function mensagemSourceAcimaDoTeto(relPath, bytes, runtime) {
398
+ return (`A source do deploy workspace tem ${emKB(bytes)} — o Core aceita no máximo ${emKB(WORKSPACE_SOURCE_MAX_BYTES)}.\n` +
399
+ ` arquivo: ${relPath}\n` +
400
+ '\n' +
401
+ ' Acima desse teto o Core responde HTTP 413 "Falha ao resolver a source do deploy",\n' +
402
+ ' que parece problema de rede/tamanho de upload e não é: é o teto do alvo.\n' +
403
+ '\n' +
404
+ ` Se "${relPath}" é um pacote de aplicação (tarball/zip) e não um handler .ts,\n` +
405
+ ' o alvo certo é vm:\n' +
406
+ ` neetru deploy --target vm --artifact "${relPath}"\n` +
407
+ (runtime === 'nextjs'
408
+ ? `\n (o neetru.config.json deste produto declara runtime "nextjs" — workspace não serve esse runtime)\n`
409
+ : ''));
410
+ }
411
+ //# sourceMappingURL=deploy-target-contract.js.map
@@ -0,0 +1,19 @@
1
+ /**
2
+ * O `--env-file` do `neetru build` (bug_25ff8581): cada linha `CHAVE=valor`
3
+ * vira variável do PROCESSO do build (o spawn do bundler), e não um `.env` que
4
+ * o bundler lê. Por isso a regra é a da CLI, mais simples que a do dotenv:
5
+ *
6
+ * KEY=value (sem aspas; o `#` depois do `=` faz parte do valor)
7
+ * KEY="value with spaces" (aspas duplas)
8
+ * KEY='value' (aspas simples)
9
+ * # comentário (ignorado)
10
+ * linha vazia (ignorada)
11
+ *
12
+ * Não suporta multi-line values nem expande `$VAR`.
13
+ *
14
+ * Mora aqui, e não em `commands/build.ts`, porque a varredura de segredo do
15
+ * deploy (`collectPublicEnvSecrets`) precisa da MESMA regra para procurar o
16
+ * valor que o build injetou (rodada final 5 do cli#81). Quem recebe o texto já
17
+ * decodificado e sem a marca BOM é quem chama.
18
+ */
19
+ export declare function variaveisDoEnvFile(conteudo: string): Record<string, string>;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * O `--env-file` do `neetru build` (bug_25ff8581): cada linha `CHAVE=valor`
3
+ * vira variável do PROCESSO do build (o spawn do bundler), e não um `.env` que
4
+ * o bundler lê. Por isso a regra é a da CLI, mais simples que a do dotenv:
5
+ *
6
+ * KEY=value (sem aspas; o `#` depois do `=` faz parte do valor)
7
+ * KEY="value with spaces" (aspas duplas)
8
+ * KEY='value' (aspas simples)
9
+ * # comentário (ignorado)
10
+ * linha vazia (ignorada)
11
+ *
12
+ * Não suporta multi-line values nem expande `$VAR`.
13
+ *
14
+ * Mora aqui, e não em `commands/build.ts`, porque a varredura de segredo do
15
+ * deploy (`collectPublicEnvSecrets`) precisa da MESMA regra para procurar o
16
+ * valor que o build injetou (rodada final 5 do cli#81). Quem recebe o texto já
17
+ * decodificado e sem a marca BOM é quem chama.
18
+ */
19
+ export function variaveisDoEnvFile(conteudo) {
20
+ const vars = {};
21
+ for (const line of conteudo.split(/\r?\n/)) {
22
+ const trimmed = line.trim();
23
+ if (!trimmed || trimmed.startsWith('#'))
24
+ continue;
25
+ const eq = trimmed.indexOf('=');
26
+ if (eq === -1)
27
+ continue;
28
+ const key = trimmed.slice(0, eq).trim();
29
+ let val = trimmed.slice(eq + 1).trim();
30
+ // Remove aspas simétricas.
31
+ if (val.length >= 2) {
32
+ const open = val[0];
33
+ const close = val[val.length - 1];
34
+ if ((open === '"' && close === '"') || (open === "'" && close === "'")) {
35
+ val = val.slice(1, -1);
36
+ }
37
+ }
38
+ if (!key)
39
+ continue;
40
+ vars[key] = val;
41
+ }
42
+ return vars;
43
+ }
44
+ //# sourceMappingURL=env-file-do-build.js.map
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Fonte única do alfabeto de ambiente de **tenant/workspace/deployment** que o
3
+ * Core aceita nas rotas `/api/cli/v1/{tenants,workspaces,deployments}`.
4
+ *
5
+ * POR QUE ESTE ARQUIVO EXISTE
6
+ * ---------------------------
7
+ * bug_7dcb68e2666a43f69ef362d2cbff94ed — a CLI oferecia (e usava como padrão)
8
+ * o token `'dev'`, que NÃO existe no enum do Core. As rotas citadas validam
9
+ * por igualdade ESTRITA contra `ENVIRONMENT_IDS`
10
+ * (`neetru-core/src/lib/schemas/envs.ts` = `['dev-local','staging','prod']`) e
11
+ * devolvem HTTP 400 `validation_failed`. Resultado: quem aceitava o default
12
+ * sugerido pela própria ferramenta tomava 400 — e o `neetru new` quebrava no
13
+ * passo [2/5]. O dev não tinha como adivinhar `'dev-local'`.
14
+ *
15
+ * O defeito estava copiado em 4 comandos (workspaces/tenants create+update/
16
+ * deployments/new). Centralizar aqui é o mesmo remédio que o Core já aplicou
17
+ * do lado servidor: um alfabeto só, para que a próxima mudança não deixe uma
18
+ * cópia para trás.
19
+ *
20
+ * ATENÇÃO — não confundir com o alfabeto de BANCO (`neetru db *`), que usa
21
+ * `'production'` (e não `'prod'`) e vive em `src/commands/db.ts`. A divergência
22
+ * é intencional do lado do Core; ver o doc de `DATABASE_ENVIRONMENTS` lá.
23
+ */
24
+ import type { NeetruCliError } from '../cli-kit/errors.js';
25
+ /** Ambientes de tenant/workspace/deployment aceitos pelo Core. */
26
+ export declare const TENANT_ENVIRONMENT_IDS: readonly ["dev-local", "staging", "prod"];
27
+ export type TenantEnvironmentId = (typeof TENANT_ENVIRONMENT_IDS)[number];
28
+ /**
29
+ * Padrão canônico. É `'dev-local'`, nunca `'dev'` — ver o cabeçalho do módulo.
30
+ */
31
+ export declare const DEFAULT_TENANT_ENVIRONMENT_ID: TenantEnvironmentId;
32
+ /** Lista legível para mensagens de erro e textos de ajuda. */
33
+ export declare function listarAmbientesTenant(): string;
34
+ /**
35
+ * Normaliza um `--env` cru para o token que o Core aceita.
36
+ *
37
+ * @returns o id canônico, ou `null` quando o valor não corresponde a nenhum
38
+ * ambiente conhecido — o chamador decide como reportar.
39
+ */
40
+ export declare function normalizarAmbienteTenant(bruto: string | undefined | null): TenantEnvironmentId | null;
41
+ /**
42
+ * Opções do prompt "Ambiente:" — mesma ordem de promoção do painel, e da
43
+ * MESMA lista que valida (P105: era uma cópia à mão de `TENANT_ENVIRONMENT_IDS`).
44
+ */
45
+ export declare const ESCOLHAS_AMBIENTE_TENANT: ReadonlyArray<{
46
+ name: string;
47
+ value: TenantEnvironmentId;
48
+ }>;
49
+ /**
50
+ * Os OUTROS vocabulários de ambiente da CLI, derivados deste alfabeto por UMA
51
+ * tabela (P105 / bug_89d2497e, item 7). Antes, `deploy.ts` tinha
52
+ * `new Set(['dev','staging','prod'])` e `build.ts`/`env.ts` repetiam
53
+ * `'dev' | 'workspace' | 'prod'` à mão em oito lugares — cópias que podiam
54
+ * envelhecer em separado, como o `--env dev` envelheceu (bug_7dcb68e2).
55
+ *
56
+ * - `deploy`: o que `neetru deploy --env` aceita e manda como
57
+ * `environmentId`. O Core aceita `dev` como apelido de `dev-local` no
58
+ * deploy (`deployRequestSchema` faz `dev → dev-local`, conferido na
59
+ * origin/main do neetru-core em 2026-10-18).
60
+ * - `runtime`: o `NEETRU_ENV` do SDK / `neetru build --target-env` /
61
+ * `neetru env switch`. `staging` vira `workspace` (o mesmo estágio
62
+ * não-dev/não-prod, com o nome que o SDK usa).
63
+ *
64
+ * A tabela é exaustiva por tipo: um ambiente novo em `TENANT_ENVIRONMENT_IDS`
65
+ * não compila até ganhar sua linha aqui.
66
+ */
67
+ export declare const VOCABULARIOS_DE_AMBIENTE: {
68
+ readonly 'dev-local': {
69
+ readonly deploy: "dev";
70
+ readonly runtime: "dev";
71
+ };
72
+ readonly staging: {
73
+ readonly deploy: "staging";
74
+ readonly runtime: "workspace";
75
+ };
76
+ readonly prod: {
77
+ readonly deploy: "prod";
78
+ readonly runtime: "prod";
79
+ };
80
+ };
81
+ export type DeployEnvironmentId = (typeof VOCABULARIOS_DE_AMBIENTE)[TenantEnvironmentId]['deploy'];
82
+ export type RuntimeEnvironmentId = (typeof VOCABULARIOS_DE_AMBIENTE)[TenantEnvironmentId]['runtime'];
83
+ /** `dev | staging | prod` — o `--env` do `neetru deploy`, na ordem de promoção. */
84
+ export declare const DEPLOY_ENVIRONMENT_IDS: readonly DeployEnvironmentId[];
85
+ /** `dev | workspace | prod` — o `NEETRU_ENV` do SDK, na ordem de promoção. */
86
+ export declare const RUNTIME_ENVIRONMENT_IDS: readonly RuntimeEnvironmentId[];
87
+ /**
88
+ * `--env` do deploy → `NEETRU_ENV` do build, pela tabela. `undefined` para
89
+ * valor fora do vocabulário do deploy (quem chama decide o padrão).
90
+ */
91
+ export declare function deployEnvParaRuntime(env: string): RuntimeEnvironmentId | undefined;
92
+ /**
93
+ * Erro único de `--env` inválido (bug_89d2497e): os valores válidos saem de
94
+ * `TENANT_ENVIRONMENT_IDS` — a MESMA lista que valida —, e o JSON leva
95
+ * `flag`, `value` e `valid` além de `error`/`message`.
96
+ */
97
+ export declare function erroAmbienteTenantInvalido(bruto: string): NeetruCliError;
98
+ /**
99
+ * Mensagem única de `--env` inválido. Mantida aqui para que todos os comandos
100
+ * falhem com o mesmo texto e o dev aprenda o alfabeto de uma vez só.
101
+ */
102
+ export declare function mensagemAmbienteInvalido(bruto: string): string;
103
+ /**
104
+ * Normaliza um `--env` vindo da linha de comando e ABORTA quando não dá para
105
+ * mapear. Falhar aqui — antes de qualquer chamada de rede — é melhor do que
106
+ * mandar lixo pro Core e traduzir um 400 genérico depois.
107
+ */
108
+ export declare function resolverAmbienteTenant(bruto: string, json?: boolean): TenantEnvironmentId;