@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
@@ -11,6 +11,8 @@
11
11
  import * as fs from 'node:fs';
12
12
  import * as path from 'node:path';
13
13
  import { randomBytes } from 'node:crypto';
14
+ import { avisarSobraDeTemporario, removerArquivo } from '../fs-seguro.js';
15
+ import { NEETRU_ENVS } from './env.js';
14
16
  /** Registry v2 vazio — usado quando o arquivo ainda não existe. */
15
17
  function emptyDbJson() {
16
18
  return { version: 2, databases: [] };
@@ -18,7 +20,8 @@ function emptyDbJson() {
18
20
  // ---------------------------------------------------------------------------
19
21
  // migrateDbJson — qualquer entrada → v2 canônico
20
22
  // ---------------------------------------------------------------------------
21
- const VALID_ENV_KEYS = ['dev-local', 'staging', 'production'];
23
+ // P105: as chaves de `ids` são o alfabeto de banco — a mesma lista que valida.
24
+ const VALID_ENV_KEYS = NEETRU_ENVS;
22
25
  function isPlainObject(value) {
23
26
  return typeof value === 'object' && value !== null && !Array.isArray(value);
24
27
  }
@@ -144,12 +147,17 @@ export function writeDbJson(filePath, data) {
144
147
  fs.renameSync(tmpPath, filePath);
145
148
  }
146
149
  catch (err) {
147
- // Best-effort: remove o temp pra não deixar lixo se algo falhou.
150
+ // Best-effort: remove o temp pra não deixar lixo se algo falhou. Não usa
151
+ // `fs.rmSync`: com acento no caminho (`C:\Users\João\...`), no Node 24 do
152
+ // Windows ele volta sem erro e não apaga (ver `lib/fs-seguro.ts`).
153
+ // `removerArquivo` apaga e confere; se ainda assim falhar, o erro que
154
+ // importa é o original, que segue abaixo — e a sobra vira aviso no stderr
155
+ // com o caminho, em vez de sumir calada (revisão do #79).
148
156
  try {
149
- fs.rmSync(tmpPath, { force: true });
157
+ removerArquivo(tmpPath);
150
158
  }
151
- catch {
152
- /* ignora — limpeza best-effort */
159
+ catch (limpeza) {
160
+ avisarSobraDeTemporario(tmpPath, limpeza);
153
161
  }
154
162
  throw err;
155
163
  }
@@ -23,8 +23,20 @@
23
23
  * Ref: glossário 0.1.4 exporta normalizeEnvId() que usa 'prod' — use-o para
24
24
  * queries inter-sistema quando disponível.
25
25
  */
26
- /** Os 3 ambientes canônicos persistidos no `.neetru/db.json`. */
27
- export type NeetruEnv = 'dev-local' | 'staging' | 'production';
26
+ import type { NeetruCliError } from '../../cli-kit/errors.js';
27
+ /**
28
+ * Os 3 ambientes canônicos persistidos no `.neetru/db.json`. Fonte única: a
29
+ * validação e a lista de "valores válidos" das mensagens saem daqui
30
+ * (bug_89d2497e — antes a lista era copiada à mão em 5 mensagens).
31
+ */
32
+ export declare const NEETRU_ENVS: readonly ["dev-local", "staging", "production"];
33
+ export type NeetruEnv = (typeof NEETRU_ENVS)[number];
34
+ /**
35
+ * Erro de `--env` inválido nos comandos de banco (bug_89d2497e): os valores
36
+ * válidos saem de `NEETRU_ENVS` e os apelidos de `ENV_ALIASES` — as mesmas
37
+ * fontes que validam. Sai como erro do cliente (exit 1), código `invalid_env`.
38
+ */
39
+ export declare function erroAmbienteBancoInvalido(input: unknown): NeetruCliError;
28
40
  /**
29
41
  * Normaliza um nome de ambiente para um dos 3 valores canônicos.
30
42
  *
@@ -32,6 +44,6 @@ export type NeetruEnv = 'dev-local' | 'staging' | 'production';
32
44
  * no stderr listando o valor canônico. Nunca normaliza silenciosamente.
33
45
  *
34
46
  * Faz lowercase + trim antes do lookup. Entrada não-string, vazia ou
35
- * desconhecida lança um `Error` que lista os valores aceitos.
47
+ * desconhecida lança o `NeetruCliError` de `erroAmbienteBancoInvalido`.
36
48
  */
37
49
  export declare function normalizeEnv(input: string): NeetruEnv;
@@ -23,6 +23,13 @@
23
23
  * Ref: glossário 0.1.4 exporta normalizeEnvId() que usa 'prod' — use-o para
24
24
  * queries inter-sistema quando disponível.
25
25
  */
26
+ import { invalidChoiceError } from '../../cli-kit/choices.js';
27
+ /**
28
+ * Os 3 ambientes canônicos persistidos no `.neetru/db.json`. Fonte única: a
29
+ * validação e a lista de "valores válidos" das mensagens saem daqui
30
+ * (bug_89d2497e — antes a lista era copiada à mão em 5 mensagens).
31
+ */
32
+ export const NEETRU_ENVS = ['dev-local', 'staging', 'production'];
26
33
  /** Mapa de aliases aceitos → valor canônico. */
27
34
  const ENV_ALIASES = {
28
35
  dev: 'dev-local',
@@ -43,6 +50,31 @@ const ALIAS_NOTICE = {
43
50
  stg: 'staging',
44
51
  prod: 'production',
45
52
  };
53
+ /** `dev/local → dev-local, stg → staging, prod → production` — de `ENV_ALIASES`. */
54
+ function apelidosLegiveis() {
55
+ const porDestino = new Map();
56
+ for (const [apelido, destino] of Object.entries(ENV_ALIASES)) {
57
+ if (apelido === destino)
58
+ continue;
59
+ porDestino.set(destino, [...(porDestino.get(destino) ?? []), apelido]);
60
+ }
61
+ return [...porDestino].map(([destino, apelidos]) => `${apelidos.join('/')} → ${destino}`).join(', ');
62
+ }
63
+ /**
64
+ * Erro de `--env` inválido nos comandos de banco (bug_89d2497e): os valores
65
+ * válidos saem de `NEETRU_ENVS` e os apelidos de `ENV_ALIASES` — as mesmas
66
+ * fontes que validam. Sai como erro do cliente (exit 1), código `invalid_env`.
67
+ */
68
+ export function erroAmbienteBancoInvalido(input) {
69
+ return invalidChoiceError({
70
+ flag: '--env',
71
+ value: typeof input === 'string' ? input : `(${typeof input})`,
72
+ valid: NEETRU_ENVS,
73
+ subject: 'Ambiente',
74
+ code: 'invalid_env',
75
+ hint: `Apelidos aceitos: ${apelidosLegiveis()}.`,
76
+ });
77
+ }
46
78
  /**
47
79
  * Normaliza um nome de ambiente para um dos 3 valores canônicos.
48
80
  *
@@ -50,20 +82,15 @@ const ALIAS_NOTICE = {
50
82
  * no stderr listando o valor canônico. Nunca normaliza silenciosamente.
51
83
  *
52
84
  * Faz lowercase + trim antes do lookup. Entrada não-string, vazia ou
53
- * desconhecida lança um `Error` que lista os valores aceitos.
85
+ * desconhecida lança o `NeetruCliError` de `erroAmbienteBancoInvalido`.
54
86
  */
55
87
  export function normalizeEnv(input) {
56
- if (typeof input !== 'string') {
57
- throw new Error(`normalizeEnv: ambiente inválido (esperava string, recebeu ${typeof input}). ` +
58
- `Valores aceitos: dev-local, staging, production.`);
59
- }
88
+ if (typeof input !== 'string')
89
+ throw erroAmbienteBancoInvalido(input);
60
90
  const key = input.trim().toLowerCase();
61
91
  const canonical = ENV_ALIASES[key];
62
- if (!canonical) {
63
- throw new Error(`normalizeEnv: ambiente "${input}" não reconhecido. ` +
64
- `Valores aceitos: dev-local, staging, production. ` +
65
- `Aliases aceitos: dev/local → dev-local, stg → staging, prod → production.`);
66
- }
92
+ if (!canonical)
93
+ throw erroAmbienteBancoInvalido(input);
67
94
  // D-4: aviso explícito quando alias não-canônico é usado
68
95
  const notice = ALIAS_NOTICE[key];
69
96
  if (notice) {
@@ -1,6 +1,10 @@
1
1
  import { type RehearseEngine } from './rehearse.js';
2
2
  import type { PipelineDeps } from './types.js';
3
- export declare function generateSql(schemaPath: string, engine?: RehearseEngine): Promise<string>;
3
+ export interface OpcoesGenerateSql {
4
+ /** Remove o `--out` temporário. Injetável só para teste. */
5
+ remover?: (dir: string) => Promise<void>;
6
+ }
7
+ export declare function generateSql(schemaPath: string, engine?: RehearseEngine, { remover }?: OpcoesGenerateSql): Promise<string>;
4
8
  /**
5
9
  * Constrói o conjunto de `PipelineDeps` de PRODUÇÃO.
6
10
  *
@@ -25,6 +25,7 @@ import * as path from 'node:path';
25
25
  import { spawn } from 'node:child_process';
26
26
  import { classifyMigration } from '@neetru/db-classifier';
27
27
  import { apiRequest } from '../api-client.js';
28
+ import { avisarSobraDeTemporario, removerDiretorio } from '../fs-seguro.js';
28
29
  import { buildRehearseInContainer, buildDockerExecFn, } from './rehearse.js';
29
30
  /**
30
31
  * Prova em COMPILE-TIME que `classifyMigration` do `@neetru/db-classifier` é
@@ -273,7 +274,7 @@ function makeTableAndIndexIdempotent(sql) {
273
274
  .replace(/CREATE TABLE (?!IF NOT EXISTS\b)/g, 'CREATE TABLE IF NOT EXISTS ')
274
275
  .replace(/CREATE (UNIQUE )?INDEX (?!IF NOT EXISTS\b)/g, (_match, unique) => `CREATE ${unique ?? ''}INDEX IF NOT EXISTS `);
275
276
  }
276
- export function generateSql(schemaPath, engine = 'postgres') {
277
+ export function generateSql(schemaPath, engine = 'postgres', { remover = removerDiretorio } = {}) {
277
278
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'neetru-drizzle-'));
278
279
  return new Promise((resolve, reject) => {
279
280
  const child = spawn('npx', [
@@ -333,8 +334,27 @@ export function generateSql(schemaPath, engine = 'postgres') {
333
334
  reject(new Error(`falha lendo o .sql gerado em ${tmpDir}: ${err.message}`));
334
335
  }
335
336
  });
336
- }).finally(() => {
337
- fs.rmSync(tmpDir, { recursive: true, force: true });
337
+ }).then(
338
+ // Limpa o --out temporário. Não usa `fs.rmSync`: o `os.tmpdir()` de quem tem
339
+ // acento na home (`C:\Users\João\AppData\Local\Temp`) faz o rmSync do
340
+ // Node 24 no Windows voltar sem erro e não apagar nada — um `neetru-drizzle-*`
341
+ // perdido por geração. `removerDiretorio` apaga e confere (ver `lib/fs-seguro.ts`).
342
+ //
343
+ // A falha da limpeza nunca derruba o resultado nem esconde o erro da
344
+ // geração, mas também não some calada: vira aviso no stderr com o caminho
345
+ // que sobrou (revisão do #79).
346
+ async (sql) => {
347
+ try {
348
+ await remover(tmpDir);
349
+ }
350
+ catch (limpeza) {
351
+ avisarSobraDeTemporario(tmpDir, limpeza);
352
+ }
353
+ return sql;
354
+ }, async (err) => {
355
+ // O erro da geração é o que importa: falha na limpeza não pode escondê-lo.
356
+ await remover(tmpDir).catch((limpeza) => avisarSobraDeTemporario(tmpDir, limpeza));
357
+ throw err;
338
358
  });
339
359
  }
340
360
  /**
@@ -16,12 +16,16 @@
16
16
  * Postgres e sem rede. A fiação real (drizzle-kit / container / HTTP) vive
17
17
  * no `buildPipelineDeps()`.
18
18
  */
19
+ import type { NeetruEnv } from '../db-local/env.js';
19
20
  /** As 5 fases do pipeline, na ordem de execução. */
20
21
  export type PipelinePhase = 'fingerprint' | 'generate' | 'rehearse' | 'classify' | 'push';
21
22
  /** Severidade global da migração — espelha o `@neetru/db-classifier`. */
22
23
  export type MigrationSeverity = 'aditiva' | 'destrutiva';
23
- /** Os 3 ambientes canônicos do `neetru db apply`. */
24
- export type ApplyEnv = 'dev-local' | 'staging' | 'production';
24
+ /**
25
+ * Os 3 ambientes canônicos do `neetru db apply` — o alfabeto de BANCO
26
+ * (`NEETRU_ENVS`, `db-local/env.ts`). P105: era a união escrita à mão.
27
+ */
28
+ export type ApplyEnv = NeetruEnv;
25
29
  /**
26
30
  * Relatório de classificação — subconjunto estrutural do `ClassificationReport`
27
31
  * do `@neetru/db-classifier`. Tipado localmente pra que o orquestrador e seus
@@ -1,20 +1,2 @@
1
- /**
2
- * `@neetru/db-pipeline` — contratos do orquestrador do `neetru db apply`.
3
- *
4
- * O pipeline roda CLIENT-SIDE as fases 1-5 do `neetru db apply`:
5
- * 1. `fingerprint` — hash determinístico do schema.
6
- * 2. `generate` — `drizzle-kit generate` produz o `.sql`.
7
- * 3. `rehearse` — ensaia o `.sql` num Postgres efêmero real.
8
- * 4. `classify` — `@neetru/db-classifier` marca aditiva/destrutiva.
9
- * 5. `push` — adquire lock + envia o artefato validado pro Core.
10
- *
11
- * O pipeline NÃO decide política — ele produz um `.sql` validado e
12
- * classificado e o envia. A decisão de aplicar (ou exigir confirmação numa
13
- * migração destrutiva) é do Core.
14
- *
15
- * Tudo aqui é deps-injetado: o orquestrador é unit-testável sem Docker, sem
16
- * Postgres e sem rede. A fiação real (drizzle-kit / container / HTTP) vive
17
- * no `buildPipelineDeps()`.
18
- */
19
1
  export {};
20
2
  //# sourceMappingURL=types.js.map
@@ -0,0 +1,152 @@
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
+ /** Alvos aceitos pelo `neetru deploy` (espelha `DEPLOY_TARGETS` do Core). */
55
+ export type DeployTarget = 'workspace' | 'cloud-run' | 'vm';
56
+ /** Runtimes declaráveis no `neetru.config.json` (espelha `RUNTIMES`). */
57
+ export type ProductRuntime = 'nextjs' | 'node-api';
58
+ /**
59
+ * Teto ABSOLUTO da source de um deploy workspace, em bytes UTF-8.
60
+ *
61
+ * Espelha `WORKSPACE_SOURCE_MAX_BYTES` do Core
62
+ * (`src/lib/schemas/deploy-request.ts`), que o aplica nos DOIS caminhos:
63
+ * `source` inline (zod `.max()`) e `sourceUrl` baixada do GCS
64
+ * (`fetchWorkspaceSource` → `SourceFetchError(413, 'source_too_large')`).
65
+ *
66
+ * A CLI tinha só o limiar de 1.5 MiB do bug_eae4bef6, que decide *inline vs
67
+ * GCS* — e nunca o teto do Core. Resultado: tudo entre 2 MiB e infinito subia
68
+ * pro GCS e voltava como 413 opaco. Conhecer o teto aqui é o que permite
69
+ * recusar local com o número real.
70
+ */
71
+ export declare const WORKSPACE_SOURCE_MAX_BYTES: number;
72
+ /** `true` quando o caminho aponta um pacote de aplicação, não um handler. */
73
+ export declare function pareceArquivoDePacote(caminho: string): boolean;
74
+ /** Quantos bytes do começo do arquivo o farejador olha. */
75
+ export declare const BYTES_FAREJADOS: number;
76
+ /**
77
+ * Olha os BYTES CRUS do começo da source de um deploy workspace e diz se ela é
78
+ * pacote/binário. Devolve o motivo em PT-BR, ou `null` quando parece texto.
79
+ *
80
+ * Por que pelo conteúdo: a recusa por extensão só olhava `--artifact`. Um
81
+ * pacote apontado pelo `source` do neetru.config.json, ou com extensão que a
82
+ * lista não prevê, só batia no teto de 2 MiB. E lido como UTF-8 um binário
83
+ * incha ~1,75x (cada byte inválido vira U+FFFD, 3 bytes), então um pacote
84
+ * abaixo de ~1,15 MiB passava no teto, subia e voltava do Core como erro de
85
+ * COMPILAÇÃO do esbuild, que não diz a causa (revisão do PR #74).
86
+ *
87
+ * Tem que receber os bytes CRUS: depois de decodificado em UTF-8 o gzip já
88
+ * virou U+FFFD e a assinatura sumiu.
89
+ */
90
+ export declare function farejarConteudoDePacote(inicio: Uint8Array): string | null;
91
+ /** Flags do `neetru deploy` que mudam de sentido conforme o `--target`. */
92
+ export interface DeployFlagsSnapshot {
93
+ artifact?: string;
94
+ artifactUrl?: string;
95
+ artifactSha256?: string;
96
+ image?: string;
97
+ registry?: string;
98
+ registryRepo?: string;
99
+ buildLocal?: boolean;
100
+ server?: string;
101
+ port?: number;
102
+ stack?: string;
103
+ /** Lido só em vm e cloud-run (`loadEnvFile`); workspace nunca olha. */
104
+ envFile?: string;
105
+ /** Usado só em vm (subdomínio do vhost). */
106
+ domain?: string;
107
+ /** Empacotamento local do tarball — só existe em vm. */
108
+ localArtifact?: boolean;
109
+ }
110
+ export interface DeployContractError {
111
+ /** Código estável — vai pro `{ok:false,error}` do `--json`. */
112
+ code: string;
113
+ /** Mensagem PT-BR que diz O QUE FAZER, não só o que está errado. */
114
+ message: string;
115
+ }
116
+ export interface DeployContractVerdict {
117
+ errors: DeployContractError[];
118
+ warnings: string[];
119
+ }
120
+ export interface DeployContractInput {
121
+ target: DeployTarget;
122
+ /** `runtime` do neetru.config.json. Ausente = sem opinião (não bloqueia). */
123
+ runtime?: string;
124
+ flags: DeployFlagsSnapshot;
125
+ }
126
+ /**
127
+ * Avalia a combinação `target × runtime × flags` ANTES de qualquer build,
128
+ * upload ou chamada ao Core.
129
+ *
130
+ * Fail-open pro desconhecido: `runtime` ausente ou fora do enum nunca bloqueia
131
+ * (repos anteriores ao campo continuam deployando). Fail-closed só no que está
132
+ * provado impossível.
133
+ */
134
+ export declare function checkDeployTargetContract(input: DeployContractInput): DeployContractVerdict;
135
+ /** De onde veio o arquivo de source de um deploy workspace. */
136
+ export type OrigemDaSource = 'artifact' | 'config' | 'padrao';
137
+ /**
138
+ * Mensagem da recusa de uma source de workspace que é pacote, achada pelo nome
139
+ * ou pelo conteúdo DEPOIS da leitura. Usa o mesmo código de erro da recusa por
140
+ * `--artifact` (`artifact_nao_eh_handler_workspace`): é o mesmo erro, achado
141
+ * por outra porta.
142
+ */
143
+ export declare function mensagemSourceNaoEhHandler(relPath: string, motivo: string, origem: OrigemDaSource): string;
144
+ /**
145
+ * Mensagem do estouro do teto de source do workspace, usada depois que a
146
+ * source já foi lida e o farejador de pacote não a recusou: na prática, um
147
+ * handler que ficou grande demais.
148
+ *
149
+ * Diz o número real, o teto real, e o alvo certo — em vez do 413 do Core, que
150
+ * diz só "Falha ao resolver a source do deploy".
151
+ */
152
+ export declare function mensagemSourceAcimaDoTeto(relPath: string, bytes: number, runtime?: string): string;