@neetru/cli 2.11.3 → 2.11.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,547 +1,561 @@
1
- # Changelog @neetru/cli
2
-
3
- Convenção: [Keep a Changelog](https://keepachangelog.com/) + [SemVer](https://semver.org/).
4
-
5
- ## [2.11.0] — 2026-05-27 (hardening: token unificado · URL allowlist · telemetry real)
6
-
7
- > Minor de hardening pós-2.10.2. Fecha 3 itens HIGH levantados na review do chefe-de-CLI (`docs/_review/CHEFE_CLI_REVIEW_2026-05-27.md` no Core) + Codex sweep (HIGH-10). Nenhuma breaking change — comandos e flags antigas seguem funcionando; warnings apontam para a deprecação prevista pra 2.12.0.
8
-
9
- ### Adicionado
10
-
11
- - **`--allow-untrusted-url` em `neetru config set`** (MASTER-HIGH-049) — flag opt-in pra setar `neetruApiUrl` fora da allowlist canônica. Sem essa flag (ou `NEETRU_ALLOW_UNTRUSTED_URL=1`) o `config set` rejeita com exit(1) + banner vermelho. Allowlist: `api.neetru.com`, `core.neetru.com`, `neetru.com` (apex), `*.neetru.com` (subdomínios), `localhost`/`127.0.0.1`/`::1` (dev HTTP ok); demais hosts exigem HTTPS.
12
- - **Telemetry real** (MASTER-HIGH-052) — `telemetry.enabled` deixou de ser flag fantasma. Quando opt-in, `neetru <comando>` agora emite evento anônimo (`{command, durationMs, ok, exitCode, ts}`) para `POST /api/sdk/v1/telemetry/log`. Identificação por `installId` UUID em `~/.config/neetru-cli/install-id` (chmod 0600). Nunca envia token, path absoluto, email, ou env. Buffer in-memory cap 50 + flush em `beforeExit` com timeout 1.5s (fire-and-forget — erro de rede não bloqueia o comando). Override: `NEETRU_TELEMETRY_DISABLED=1`.
13
-
14
- ### Mudado (compat-friendly)
15
-
16
- - **Token resolver unificado** (MASTER-HIGH-048) — `api-client.ts` (`apiRequest` + `apiStream`) agora o Bearer token via `getActiveTokenSync()` (`src/lib/token-resolver.ts`), que prefere `~/.config/neetru-cli/auth.json` (canônico desde Sprint 1) sobre o Conf storage (legacy). Quando o token vem do Conf, emite warning one-shot stderr alertando deprecação pra 2.12.0. 8 comandos que liam `config.get('neetruApiKey')` direto (`status`, `validate`, `deploy`, `vm`, `logs`, `doctor`, `publish`, `whoami`) migrados pra `getActiveTokenSync()`. Comportamento anterior "logado pra `whoami` mas não pra `status`" quando o token só existia em `auth.json` — desaparece.
17
- - **`neetru config set neetruApiKey` emite deprecation warning** o setter manual continua funcionando, mas avisa que `neetru login` é o caminho canônico (que grava em `auth.json` chmod 0600). Storage Conf de `neetruApiKey` será removido em 2.12.0.
18
- - **`apiRequest` emite warning one-shot quando host customizado fora da allowlist** — defesa em profundidade pra casos em que o owner já tem URL untrusted em Conf (não pegou o `config set` 2.11).
19
-
20
- ### Infraestrutura de testes (+34 tests)
21
-
22
- - **Novo `src/__tests__/url-allowlist.test.ts`** (15 cases): hosts trusted + edge cases (domain confusion `neetru.com.evil.com`, HTTP em prod, protocolos não suportados).
23
- - **Novo `src/__tests__/config-set-allowlist.test.ts`** (7 cases): rejeita default, aceita com `--allow-untrusted-url`, aceita com env override.
24
- - **Novo `src/__tests__/token-resolver.test.ts`** (4 cases): precedência `auth.json > Conf > null` + warning one-shot stderr.
25
- - **Novo `src/__tests__/telemetry.test.ts`** (8 cases): opt-in default off + env override, happy path POST com payload validado, idempotência do flush, falha de rede engolida, cap de buffer, privacy (zero token/path/email no payload).
26
- - 7 tests existentes ganharam `readAuthJsonSync: vi.fn(() => null)` no mock de `auth.js` (control-plane, workspaces, products-create, sdk-credential, new-browser-optin, doctor, publish) preserva semântica antiga de "token via config.set" caindo no fallback Conf.
27
- - `vitest.config.ts` seta `NEETRU_SUPPRESS_LEGACY_WARNINGS=1` em test setup pra não poluir CI com banner de deprecation.
28
-
29
- ### Deprecation timeline
30
-
31
- - **2.11.0 (esta release):** Conf `neetruApiKey` ainda funciona (com warning); login grava em ambos os storages.
32
- - **2.12.0 (planejado):** `login` para de gravar em Conf; `config set neetruApiKey` continua aceito mas vira no-op com warning; `Conf neetruApiKey` removido do schema. Owner que copia binário pra outra máquina precisa garantir migração `~/.config/neetru-cli/auth.json`.
33
-
34
- ### Sem breaking change
35
-
36
- - Todos os comandos e flags da 2.10.x seguem funcionando.
37
- - Endpoints API canônicos inalterados.
38
- - Path padrão `~/.config/neetru-cli/auth.json` continua canônico.
39
-
40
- ---
41
-
42
- ## [2.10.2] — 2026-05-27 (patch: paths broken em produção + autocomplete drift)
43
-
44
- > Patch urgente — chefe-de-CLI review do dia (`docs/_review/CHEFE_CLI_REVIEW_2026-05-27.md` no Core) + `MASTER_PLAN_2026-05-27.md` §4 Bloco G. Quatro endpoints quebrados em produção (404 silencioso ou rota inexistente) + cobertura de autocomplete em ~45% silenciosamente. Sem nada novo de UI ou behavior — só fix de quem já estava 404'eando.
45
-
46
- ### Corrigido (CRITICAL)
47
-
48
- - **MASTER-CRIT-035 `neetru promote` apontava pra endpoint inexistente.** `src/commands/promote.ts:104` chamava `/cli/v1/promotion/request` (sem prefixo `/api`) → 404 sempre. Pior: o handler de 404 ainda mascarava o erro com "Endpoint ainda não disponível, entra em build no Sprint 11" — a rota existe há sprints sob `/api/cli/v1/promotion/request`. Fixado. Handler de 404 agora reporta erro real (exit 5). Test cúmplice `promote.test.ts:110` atualizado (pinava `/cli/v1/...` como correto).
49
- - **MASTER-CRIT-036 — `neetru agent release` apontava pra endpoint inexistente.** `src/commands/agent-release.ts:215` chamava `/cli/v1/agent/release`. Trocado pra canônico `/api/cli/v1/agent/release`.
50
- - **MASTER-CRIT-037 `neetru fn deploy` removido (rota nunca existiu).** `src/commands/fn.ts` apontava pra `/cli/v1/fn/deploy` — não há rota em `/api/**/fn/**` no Core. Comando deletado por inteiro (arquivo + import em `src/index.ts` + entry em autocomplete + test cúmplice `src/__tests__/fn.test.ts` que pinava o path errado). Reintroduzir quando/se a feature for de fato implementada server-side.
51
-
52
- ### Corrigido (HIGH)
53
-
54
- - **MASTER-HIGH-050 — `neetru logs` apontava pra alias legacy.** `src/commands/logs.ts:106` usava `/api/v1/cli/logs` (inversão dos prefixos). O alias legacy ainda existe no Core mas tem deprecation prevista para 2026-07-01 — depois disso `neetru logs` morre sem aviso. Trocado pra canônico `/api/cli/v1/logs`.
55
- - **MASTER-HIGH-051 — autocomplete cobria só ~45% dos comandos.** `TOP_LEVEL_COMMANDS` em `src/commands/autocomplete.ts` listava 22 entries de um total de ~50 comandos top-level expostos em `src/index.ts`. Bash/zsh/pwsh completion silenciosamente broken para a maioria das operações (auth, admin, customers, tenants, audit, billing, servers, workspaces, deployments, cloud-run, api-catalog, products, vm, support, bug, dns, hosting, builds, dr, docs, …). Reescrito para incluir TODOS os ≈50 comandos, em ordem alfabética. Aliases incluídos (`menu` → `ui`, `ar` → `artifact-registry`).
56
-
57
- ### Infraestrutura de testes (regression guards)
58
-
59
- - **Novo: `src/__tests__/endpoint-paths.regression.test.ts`** — varre `src/commands/**/*.ts` extraindo o primeiro argumento de toda chamada `apiRequest(...)` / `apiStream(...)` e valida que começa com prefixo canônico: `/api/cli/v1/`, `/api/sdk/v1/`, `/api/v1/`, ou `/api/internal/`. Allowlist explícita só pra `/api/health` (Cloud Run healthcheck). Três testes: prefixo canônico, zero `/cli/v1/*` cru (vetor dos CRIT-035..037), zero `/api/v1/cli/*` invertido (vetor do HIGH-050).
60
- - **Novo: `src/__tests__/top-level-commands-coverage.regression.test.ts`** — parse simples de `src/index.ts` extraindo `program.command('X')`; exige cobertura ≥95% em `TOP_LEVEL_COMMANDS` + zero entries fantasma + ordem alfabética. Detecta drift do autocomplete quando alguém adicionar/remover comando no `index.ts` no futuro.
61
-
62
- ### Sem mudança
63
-
64
- - Comportamento do CLI fora dos 4 fixesidêntico ao 2.10.1.
65
-
66
- ---
67
-
68
- ## [2.10.0] 2026-05-27 (rename: `neetru marketplace` `neetru archive` · fonte agora pública)
69
-
70
- ### BREAKING
71
-
72
- - **`neetru marketplace` foi renomeado para `neetru archive`.** Subcomandos preservados (`skills install/update/list/uninstall`, `sdk init/templates/add`, `browse`). NÃO há alias de retrocompat — o comando antigo deixa de existir nesta versão. Quem rodava `neetru marketplace skills install` em scripts CI precisa trocar para `neetru archive skills install`.
73
- - **Cache local mudou de `~/.neetru/marketplace-cache/` para `~/.neetru/archive-cache/`.** Caches antigos podem ser apagados manualmente (não migração automática `archive skills install` cria o novo limpo). A função `getSkillsSourceDir` mantém retrocompat detectando o nível `claude-skills/` caso o cache de uma versão anterior do `archive-cache` ainda tenha esse layout.
74
- - **Variável de ambiente `NEETRU_MARKETPLACE_SYMLINK` virou `NEETRU_ARCHIVE_SYMLINK`** (Windows). Quem usava precisa renomear.
75
-
76
- ### Mudado
77
-
78
- - **Fonte de skills migrou de `github.com/Neetru/neetru-libs` (privado) para `github.com/Neetru/neetru-libs-public` (público).** O `neetru-libs` privado mantém `packages/` (`@neetru/db-classifier`, `sql-guard`, `pii-mask`, `neetru-glossario`) `claude-skills/` foi exposto, via `git subtree push --prefix=claude-skills`. Resultado: `neetru archive skills install` deixa de exigir `gh auth setup-git` ou `GITHUB_TOKEN` — clone anônimo funciona.
79
- - **Layout do clone público é mais flat:** `plugins/<plugin>/skills/<skill>/SKILL.md` no topo (em vez de `claude-skills/plugins/...`). O resolver detecta o layout legado automaticamente — caches antigos continuam resolvendo até o próximo `archive skills update`.
80
-
81
- ### Por quê
82
-
83
- - O 2.9.13 quebrava em `git clone` quando `neetru-libs` virou privado (HTTP 401 sem credencial git configurada). O fix arquitetural certo era separar o catálogo público de skills do código proprietário em `packages/` — `neetru-libs-public` é esse catálogo. A renomeação `marketplace → archive` aproveitou o break pra alinhar o nome do comando ao conceito real (catálogo/arquivo de artefatos, não um marketplace transacional).
84
-
85
- ## [2.9.13] — 2026-05-26 (feat: force-cleanup recovery + mfa-status observability)
86
-
87
- ### Adicionado
88
-
89
- - **`neetru servers force-cleanup <serverId> --reason "..." [--yes] [--json]`** — recovery quando VM stuck (status=timeout_agent_register/falha_provisionamento/provisionando >30min) e flow normal (`deactivate`/`delete` com MFA) não funciona. NÃO exige MFA (bypass intencional pra desbloquear deadlock — bug_c42fa12b CRITICAL quando MFA broken via bug_84e4dacb). Double-confirm interativo: usuário digita o serverId. Audit pesado + notification all staff garantem accountability. Bate em POST `/api/cli/v1/servers/[id]/force-cleanup`.
90
- - **`neetru auth mfa-status [--json]`** — observability MFA do usuário atual: enrolled, enrolledAt, lastUsedAt, hasEncryptedSecret, recoveryCodesCount, hint acionável (clock skew vs nunca usado vs zero recovery codes vs MFA não enrolled). Bate em GET `/api/cli/v1/auth/mfa/status`. Útil quando `servers deactivate` rejeita TOTP e owner precisa debugar antes de tentar novamente.
91
-
92
- ### Corrige (HIGH/CRITICAL)
93
-
94
- - **bug_c42fa12b1e194a0794f14ea74994e2a3 (CRITICAL) — Deadlock VM stuck + MFA broken.** force-cleanup destrava recovery sem precisar MFA. Pré-condições rígidas + audit pesado mitigam risco de uso indevido.
95
- - **bug_84e4dacbcaf14ea09ae9825ff2e2b9f3 (HIGH) — MFA TOTP rejeita opaco.** mfa-status mostra `lastUsedAt=null` indicando "MFA enrolled mas nunca usou com sucesso" + sugere causas comuns (clock skew, secret desync).
96
-
97
- ## [2.9.12] 2026-05-26 (fix: libuv crash MFA error path + lint guard process.exit)
98
-
99
- ### Corrigido (MEDIUM regressão libuv em MFA)
100
-
101
- - **bug_6362578edfd7498dbcfe59853181be20 (MEDIUM) — `Assertion failed: !(handle->flags & UV_HANDLE_CLOSING)` voltou em CLI 2.9.9 em error path do MFA.**
102
- Reprodução: `neetru servers deactivate <id> --yes --mfa-token=<code> --json` quando o servidor retorna 403 (código MFA inválido ou expirado).
103
- Causa raiz: o fix anterior (bug_818cf6d, 2.9.9) cobriu apenas `build.ts`. Os outros error paths `handleApiError` em `cli-read.ts`, `resolveStepUp` em `cli-write.ts`, `failLookup`/`failInput` em `pickers.ts`, e todos os ~200 pontos de `process.exit()` em 46 arquivos de comando continuavam chamando `process.exit()` direto após I/O async (fetch 403, inquirer prompts, readline MFA). Em Windows o libuv assertion é fatal.
104
- Fix: sweep completo46 arquivos de comando + 4 arquivos de lib (`cli-read`, `cli-write`, `pickers`, `iam-preflight`) convertidos para `safeExit(N)`.
105
-
106
- ### Infraestrutura de testes (guard antirregressão)
107
-
108
- - **Novo teste `src/__tests__/regressions/no-direct-process-exit.regression.test.ts`** varre `src/commands/**/*.ts` e `src/lib/**/*.ts` e FALHA se encontrar qualquer `process.exit(` direto. Detecta regressões desta classe automaticamente em CI. Arquivos isentos: `utils/safe-exit.ts` (a implementação em si). Adição de `// safe-exit-exempt: <razão>` numa linha permite marcar exits síncronos intencionais sem quebrar o guard.
109
-
110
- ## [2.9.9] — 2026-05-25 (fix: libuv crash Windows + npm ci file lock)
111
-
112
- ### Corrigido (2 MEDIUM Windows compat)
113
-
114
- - **bug_818cf6d507b94c81a23b205eb9d18d71 (MEDIUM) — CLI crashava com `Assertion failed: !(handle->flags & UV_HANDLE_CLOSING)` em Windows.**
115
- Causa raiz: handles libuv (http keep-alive, stdin/stdout, ora spinner setInterval) ficavam em `UV_HANDLE_CLOSING` quando `process.exit(1)` matava o loop bruscamente. Em Linux/Mac libuv só warna; em Windows é assertion fatal.
116
- Fix: novo `src/utils/safe-exit.ts` com `safeExit(code): never` que faz cleanup explícito antes do exit (stopAllSpinners + destroy stdin + destroy http/https globalAgent). Build agora usa `safeExit(1)` em vez de `process.exit(1)` no catch. Spinners registrados via `registerSpinner()` (novo `src/utils/spinner-registry.ts`) pra cleanup centralizado.
117
-
118
- - **bug_93f984a16ad64656af2230583b7e554f (MEDIUM)`neetru build` quebrava com EPERM unlink quando `next dev` rodando em paralelo.**
119
- Causa raiz: `npm ci` deletava `node_modules/@next/swc-*` que o dev server tinha aberto em file lock no Windows.
120
- Fix: trocado `npm ci` por `npm install --no-save --no-audit --no-fund` (respeita locks parciais). Nova flag `--no-install` permite skip total quando o dev sabe que `node_modules` está pronto. Warn explícito em Windows orientando pausar dev server.
121
-
122
- ### Novidades técnicas
123
-
124
- - **`src/utils/safe-exit.ts`**`safeExit(code): never` + `setSafeExitCode(code): void` com cleanup robusto de handles libuv.
125
- - **`src/utils/spinner-registry.ts`** — registry global de spinners ora pra cleanup centralizado em error paths.
126
- - **`neetru build --no-install`** pula `npm install` (assume `node_modules` pronto).
127
-
128
- ### Testes
129
-
130
- - `src/__tests__/safe-exit.test.ts` 9 testes novos (spinner-registry: 6, safeExit: 3).
131
-
132
- ## [2.9.7] — 2026-05-25 (fix: URI Artifact Registry completa + Cloud Build remoto + Dockerfile template 3 CRITICAL/HIGH bugs deploy cloud-run)
133
-
134
- ### Corrigido (CRITICAL/HIGH deploy cloud-run bloqueado para gestovendas)
135
-
136
- - **bug_467db337ea9749a4b85d270d4e10576f (CRITICAL) — `neetru deploy` gerava URI Artifact Registry malformada.**
137
- URI original: `us-central1-docker.pkg.dev/gestovendas:tag` (só 2 segmentos — inválida).
138
- URI correta: `us-central1-docker.pkg.dev/{project}/{repo}/{image}:{tag}` (4 segmentos obrigatórios do AR).
139
- Fix: `buildArtifactRegistryUri` resolve o project via `gcloud config get-value project` quando o
140
- `--registry` passado contém apenas o host. O repo é inferido como `{slug}-{env}` ou explicitado via
141
- `--registry-repo`. Quando `--registry` já contém `host/project/repo` (3 segmentos), é usado diretamente.
142
- Suporta 3 formatos de `--registry`:
143
- - Host apenas: `us-central1-docker.pkg.dev` → descobre project via gcloud config.
144
- - Host + project: `us-central1-docker.pkg.dev/neetru` infere repo.
145
- - Host + project + repo: `us-central1-docker.pkg.dev/neetru/gestovendas-staging` → usa direto.
146
-
147
- - **bug_0a551e02295b42b9894f6eb6b13887b3 (CRITICAL) — `neetru deploy --target=cloud-run` exigia docker local.**
148
- Docker Desktop não é viável em Windows dev machine (5+ GB, requer WSL2, reboot) nem em CI headless.
149
- Fix: pipeline substituído por `gcloud builds submit --tag=<uri> [--project=<id>] <cwd>` (Cloud Build
150
- remoto). Não exige Docker instalado apenas `gcloud` autenticado (já feito via `neetru bootstrap`).
151
- `--build-local` força o comportamento anterior (docker build + push) para devs que preferem build local.
152
-
153
- - **bug_1904ba55feeb480690eb8a7f00b4a7b7 (HIGH) `--stack=node` sem Dockerfile terminava com erro pouco acionável.**
154
- Fix: quando `--stack=node` ou `--stack=nextjs` e não `Dockerfile` no projeto, o CLI gera
155
- automaticamente um template adequado no `cwd` antes de chamar o Cloud Build, e apaga ao terminar.
156
- Templates:
157
- - `node`: `FROM node:22-slim` + `npm ci --omit=dev` + `CMD ["node", "server.js"]` + porta 8080.
158
- - `nextjs`: multi-stage com standalone output + `COPY .next/standalone` + porta 8080.
159
- - `docker`: continua exigindo Dockerfile manual (com mensagem de erro clara).
160
- Aviso `log.warn` antes de gerar o template para o dev saber o que aconteceu.
161
-
162
- ### Adicionado
163
-
164
- - **`--registry-repo <name>`** flag opcional para especificar o nome do repositório AR explicitamente.
165
- Se omitido, inferido como `{productSlug}-{env}` (ex: `gestovendas-staging`).
166
- - **`--build-local`** — força `docker build` local em vez do Cloud Build remoto.
167
- - **`--stack=nextjs`**novo valor suportado em `neetru deploy`, gera Dockerfile Next.js standalone.
168
- - **`DeployOptions.json?: boolean`** campo para propagação de modo JSON em preflight IAM checks.
169
-
170
- ### Testes
171
-
172
- - `src/__tests__/deploy-image-uri.test.ts` 10 casos cobrindo `buildArtifactRegistryUri` (segmentos, tag sanitização, REGRESSÃO original).
173
- - `src/__tests__/deploy-cloud-build.test.ts` 5 casos cobrindo Cloud Build remoto vs docker local.
174
- - `src/__tests__/deploy-dockerfile-template.test.ts` 7 casos cobrindo geração/limpeza de template, node/nextjs/docker, warning, existente não sobrescrito.
175
-
176
- ## [2.9.6] — 2026-05-25 (fix: 3 HIGH Windows compat — bug_ec17af + 0cf14fba + 6001c5e)
177
-
178
- ### Corrigido
179
-
180
- - **bug_ec17af083d7045a1a00f24255efb716c — `neetru deploy --target=cloud-run --artifact=<file>` rejeita silenciosamente.**
181
- `--artifact` (tarball source) é incompatível com `target=cloud-run` que exige imagem de container OCI.
182
- Adicionada verificação explícita em `runCloudRunDeploy`: quando `--artifact` ou `--artifact-url` é passado
183
- com `target=cloud-run`, o CLI sai com `exit 1` e exibe mensagem orientadora com as 3 alternativas corretas:
184
- `--image <uri>`, `--registry <host>` (build automático) e `--target=vm` (que aceita tarball).
185
- Anteriormente a flag era silenciosamente ignorada, levando ao erro críptico "Sem imagem pra deployar".
186
-
187
- - **bug_0cf14fba40ec4352b75f3af2467e24b0`neetru build` quebra em Windows com scripts npm unix-only.**
188
- Scripts como `NODE_ENV=production next build` usam sintaxe de variável de ambiente Unix incompatível
189
- com `cmd.exe`. Adicionada função `detectsUnixEnvPrefix` em `buildNode`: quando `process.platform === 'win32'`
190
- e o script `build` do `package.json` contém prefixo de env Unix (padrão `VAR=val ...`), o CLI emite
191
- warning orientador antes de tentar rodar. O warning lista as 2 soluções: adicionar `cross-env` ao script,
192
- ou remover o prefixo (Next.js já usa `production` por padrão em `next build`).
193
- O build prossegue mesmo com o warning (shell=true no spawn já torna compatível em muitos casos).
194
-
195
- - **bug_6001c5e83c764428ae39a5d6a1f8be82 `neetru build` falha com tar em paths com drive-letter Windows.**
196
- GNU tar (MSYS2/Git Bash) interpreta `S:` como host SSH, causando "Cannot connect to S: resolve failed".
197
- Correção dupla em `tarDirectory` (e `buildDocker`):
198
- 1. `--force-local` adicionado automaticamente quando `process.platform === 'win32'` instrui o GNU tar
199
- a não interpretar nomes de arquivo como endereços remotos (ignorado pelo bsdtar nativo do Windows 10+).
200
- 2. `normalizePathForTar()`: converte `S:\Documents\...` → `/S/Documents/...` antes de passar pro tar,
201
- compatível com ambos os tars (GNU e BSD).
202
- Workaround manual do usuário (`tar --force-local -czf ...`) agora está embutido automaticamente no CLI.
203
-
204
- ## [2.9.3] 2026-05-25 (fix HIGH: branch NoSQL no db apply Bug 11 Fase 1)
205
-
206
- ### Corrigido
207
-
208
- - **Bug 11 Fase 1 — `neetru db apply` era SQL-only; branch NoSQL nunca era alcançada.**
209
- Adicionada detecção de engine em `runDbApply`: quando `engine {nosql-vm, firestore-instance}`,
210
- o pipeline SQL (drizzle-kit + Postgres efêmero + classify) é completamente ignorado.
211
- A nova função `runNoSqlApply` calcula o fingerprint SHA-256 do `schema.ts` local e envia
212
- `POST /api/cli/v1/db/apply` com `schemaDefinition: null` (Fase 1sem JSON Schema export).
213
- O Core registra o snapshot em `product_db_schema_snapshots/{id}` (implementado em commit `116f0d60`).
214
- Saída interativa: spinner `"Aplicando schema NoSQL (sem rehearse engine schemaless)…"`.
215
- Saída `--json`: `{ ok, status, engine, snapshotId, fingerprint, dryRun }`.
216
- `--dry-run` calcula fingerprint mas não envia ao Core (status `dry_run`).
217
- O pipeline SQL para `cloud-sql-*` e `vm-*` permanece intacto — sem regressão.
218
-
219
- ## [2.9.2] — 2026-05-25 (ux: cliente padrão Neetru automático)
220
-
221
- ### Melhorado
222
-
223
- - **`neetru workspaces create` `--customer` agora opcional para produtos Neetru-owned.**
224
- Quando o produto selecionado pertence à Neetru (`ownedBy='neetru'`, `ownerTeam='Neetru Core'`
225
- ou slug na lista conhecida), o CLI detecta via API e pula o prompt de cliente automaticamente.
226
- Em modo interativo exibe `"Cliente omitidoproduto Neetru detectado. Usando cliente interno automaticamente."`.
227
- Em modo `--json`, envia `customerId` ausente; o Core injeta o customer interno (`isNeetruInternal=true`).
228
- Para produtos de terceiros, `--customer` continua obrigatório (erro acionável com instruções de criação).
229
-
230
- - **`neetru tenants create` mesma lógica de auto-default.**
231
- Prompt de `customerId` pulado automaticamente quando produto é Neetru-owned.
232
-
233
- - **`neetru workspaces create` mensagem de confirmação no output.**
234
- Quando `--customer` não é fornecido, exibe `"Cliente: Neetru Tecnologia (interno) — auto-detectado pelo produto Neetru."`.
235
-
236
- ## [2.9.1] — 2026-05-25 (security: 5 HIGH fixes)
237
-
238
- ### Corrigido (segurança)
239
-
240
- - **HIGH-1 `db apply --json` selecionava o primeiro banco silenciosamente com múltiplos bancos.**
241
- Em modo não-interativo (`--json` ou `--yes` sem TTY), se `.neetru/db.json` tiver N > 1 bancos
242
- e `--db` não for passado, o CLI agora emite erro estruturado em vez de aplicar no primeiro banco.
243
- Saída JSON: `{ ok: false, error: "db_required", message: "...", available: [...] }`.
244
- Em CI isso evitava migração silenciosa no banco errado.
245
-
246
- - **HIGH-2 — Abertura de URL no Windows usava `cmd /c start` sem validação de protocolo.**
247
- URLs derivadas de config podiam conter caracteres de injeção de shell (`& malicious.exe`).
248
- Nova função `safeOpenUrl` valida `^https?://` antes de qualquer chamada de sistema e usa
249
- `rundll32 url.dll,FileProtocolHandler` (sem shell) no Windows. Aplica em `open.ts` e
250
- `workspaces.ts` (que agora delega para `safeOpenUrl`).
251
-
252
- - **HIGH-3 — `db init` gravava stub local em `.neetru/db.json` antes de registrar no Core.**
253
- Falha de rede/400 do Core deixava entrada órfã e re-rodar `db init` adicionava banco duplicado.
254
- Agora o registro no Core acontece primeiro; `.neetru/db.json` é escrito após sucesso.
255
-
256
- - **HIGH-4 `marketplace sdk add <template>` aceitava path traversal.**
257
- `path.join(templatesDir, templateName)` aceitava `../../etc/passwd` como nome.
258
- Adicionada whitelist `ALLOWED_SDK_TEMPLATES` e verificação `startsWith(resolve(templatesDir) + sep)`
259
- como defesa em profundidade.
260
-
261
- - **HIGH-5 `docs publish` usava path absoluto Windows como slug.**
262
- Path como `C:/Users/dev/projeto/docs/intro.md` virava slug `C:/Users/dev/projeto/docs/intro`,
263
- expondo estrutura de filesystem. `deriveSlugFromPath` agora converte para relativo via
264
- `path.relative(cwd, file)` e rejeita slugs com `:`, `..` ou `/` inicial.
265
-
266
- ## [2.8.2]2026-05-25 (fix UX slug conflict + docs open)
267
-
268
- ### Corrigido
269
-
270
- - **Bug #31 — `neetru new` não falha seco em conflito de slug.**
271
- Quando o Core retorna 400 com "Já existe um produto com o slug X", o CLI
272
- agora exibe o produto existente (nome, ID, status) e oferece um prompt
273
- interativo com três opções:
274
- 1. Vincular este projeto local ao produto existente (escreve `.neetru/config.json`
275
- apontando para o `productId`).
276
- 2. Criar com slug diferente — lista sugestões (`gestovendas-v2`, `-2`, etc.)
277
- ou permite digitar um slug livre.
278
- 3. Cancelar.
279
- Removida a mensagem "Tente manualmente: neetru products create --slug <mesmo-slug>"
280
- que sugeria repetir exatamente o comando que vai falhar de novo.
281
- O fallback genérico cobre qualquer 400 cujo `message` contenha "Já existe",
282
- "slug", "already exists" ou "duplicate".
283
-
284
- - **Bug #26 — `neetru docs` não abria documentação ao vivo.**
285
- O comando `neetru docs` era exclusivamente um registry CRUD (publish/list/get/delete)
286
- e não tinha forma de acessar a documentação pública. Adicionado:
287
- - `neetru docs open [topic]` — abre `https://core.neetru.com/docs` (ou seção
288
- específica) no browser padrão. Tópicos: `sdk`, `cli`, `db`, `webhooks`, `auth`,
289
- `billing`, `observability`, `infra`, `dns`, `deploy`, `architecture`.
290
- - `neetru docs open` sem argumento abre o índice geral.
291
- - Argumentos desconhecidos abrem busca: `core.neetru.com/docs?q=<query>`.
292
- - No menu interativo (`neetru ui`), "Docs live" agora exibe "Abrir documentação
293
- no navegador" como primeira opção antes das opções de registry.
294
-
295
- ### Notas de uso
296
-
297
- ```
298
- neetru docs open # abre core.neetru.com/docs
299
- neetru docs open sdk # vai direto pra referência do SDK
300
- neetru docs open webhooks # manual de runtime/webhooks
301
- ```
302
-
303
- ## [2.8.1] 2026-05-25 (marketplace)
304
-
305
- ### Adicionado
306
-
307
- - **`neetru marketplace`** central de artefatos do ecossistema Neetru.
308
- - `neetru marketplace skills install` — clona `Neetru/neetru-libs` em
309
- `~/.neetru/marketplace-cache/` e instala skills em `~/.claude/skills/`.
310
- Linux/macOS: symlink (atualizações automáticas via git pull).
311
- Windows: cópia recursiva (sem exigir Developer Mode).
312
- - `neetru marketplace skills update` — git pull no cache + re-copia skills
313
- instaladas como cópia (symlinks são atualizados pelo pull).
314
- - `neetru marketplace skills list` tabela com nome, versão, status e
315
- descrição de cada skill disponível no cache local.
316
- - `neetru marketplace skills uninstall` — remove skills de `~/.claude/skills/`
317
- com confirmação interativa (bypass via `--yes`).
318
- - `neetru marketplace sdk init` — adiciona `@neetru/sdk@^2.1.0` ao
319
- `package.json` do projeto atual e cria `src/neetru.ts` com boilerplate
320
- de `createNeetruClient`. Idempotente — não sobrescreve arquivo existente.
321
- - `neetru marketplace sdk templates` lista templates disponíveis em
322
- `templates/` da instalação do CLI.
323
- - `neetru marketplace sdk add <template>` copia template de feature
324
- (auth/billing/usage/support/users) pra `src/` do projeto atual.
325
- - `neetru marketplace browse` abre `https://github.com/Neetru/neetru-libs`
326
- no browser (start/open/xdg-open por plataforma).
327
- - **Menu interativo** item **"Marketplace"** adicionado ao menu principal
328
- (entre Suporte e Docs live) com sub-menu completo: skills (instalar /
329
- atualizar / listar / remover) + SDK (init / add template / listar / docs)
330
- + abrir no GitHub.
331
-
332
- ## [2.7.5] 2026-05-20 (fix do crash no upgrade)
333
-
334
- ### Corrigido
335
-
336
- - `neetru upgrade` não crasha mais ao terminar. O comando chamava
337
- `process.exit(0)` logo após o `fetch` ao npm no Windows isso
338
- derrubava o libuv com `Assertion failed: !(handle->flags &
339
- UV_HANDLE_CLOSING)` (`async.c`), porque o socket do undici (fetch
340
- nativo) ainda estava em teardown. Agora o comando só retorna; o event
341
- loop drena sozinho (o undici unref nos sockets idle) e o processo
342
- encerra limpo na hora.
343
-
344
- ## [2.7.4] 2026-05-20 (submenus redesenhados)
345
-
346
- ### Adicionado
347
-
348
- - Submenu **"Começar um projeto"** no menu principal — reúne o scaffold
349
- local (`neetru init`), a criação completa (`neetru new`) e uma tela de
350
- info sobre o `@neetru/sdk` (o que é, como instalar e consumir).
351
- - Os 10 submenus ganharam o **mesmo visual do menu principal**: moldura
352
- azul-marinho, marcador `> <` no item ativo e navegação por setas — em
353
- coluna única, alinhada à esquerda.
354
-
355
- ### Corrigido
356
-
357
- - Submenu não engole mais a primeira seta. O menu principal entregava o
358
- stdin pausado / fora de raw mode pro submenu, e o inquirer perdia a
359
- 1ª tecla — só respondia depois de um toque inicial. Agora o stdin fica
360
- "quente" na entrega; a seta funciona de cara.
361
-
362
- ## [2.7.3]2026-05-20 (polish do cabeçalho)
363
-
364
- ### Mudado
365
-
366
- - Cabeçalho do `neetru` interativo: logo renderizado **ao lado** do texto
367
- (antes era acima), com a sessão e a versão alinhadas à direita do logo.
368
- - Paleta de contorno do menu e do logo ajustada para um azul mais suave.
369
-
370
- ## [2.7.2] — 2026-05-20 (aviso de versão + menu em 2 colunas)
371
-
372
- ### Adicionado
373
-
374
- - O cabeçalho do `neetru` interativo mostra a **versão instalada** (`v2.7.2`)
375
- ao lado do usuário logado. Quando há uma versão mais nova publicada no
376
- npm, aparece uma linha **amarela** avisando pra rodar `neetru upgrade`.
377
- A checagem tem timeout curto e é à prova de falha — offline não trava o
378
- CLI.
379
- - Menu principal redesenhado em **duas colunas**, com navegação por setas
380
- (↑/↓/←/→) e contorno azul-marinho; o item ativo é marcado com `> <`.
381
-
382
- ## [2.7.1] 2026-05-20 (UI do CLI interativo)
383
-
384
- ### Adicionado
385
-
386
- - Logo Neetru em ANSI truecolor no cabeçalho do `neetru` interativo.
387
- - Cabeçalho mostra o usuário logado (email), lido localmente do
388
- `auth.json` sem chamada de rede.
389
- - Menu principal com o nome do recurso + uma descrição curta abaixo,
390
- quando útil.
391
-
392
- ### Corrigido
393
-
394
- - O CLI interativo não encerra mais sozinho: comandos que chamavam
395
- `process.exit()` em erro (ex.: "Nenhum server encontrado") matavam o
396
- menu inteiro. Agora o erro é capturado e o CLI volta ao menu — só
397
- "Sair" (ou Ctrl+C) encerra.
398
-
399
- ## [2.7.0] — 2026-05-20 (Fluxo de Ambientes Fase 3 — destino cloud-run)
400
-
401
- ### Adicionado
402
-
403
- - `neetru deploy --target=cloud-run` caminho de deploy pro destino Cloud Run
404
- dedicado. Aceita `--image <uri>` (imagem de container já buildada e pushada)
405
- ou faz `docker build` + `docker push` automático via `--registry <host>`
406
- (Artifact Registry). O destino `cloud-run` agora aparece no menu interativo.
407
-
408
- ### Mudado
409
-
410
- - `neetru promote` vocabulário de estágios migrado para `dev | staging | prod`
411
- (antes `dev/workspace/beta/prod`). Gates: 24h em `dev→staging`,
412
- 168h + canary em `staging→prod`.
413
- - `neetru deploy --target` sem valor default; omitir abre o menu interativo
414
- (workspace / cloud-run / vm). Modo não-interativo continua assumindo `vm`.
415
-
416
- ## [2.0.0] — 2026-05-06 (Sprint 12 — CLI estabilizada)
417
-
418
- ### Adicionado
419
-
420
- - `neetru doctor` diagnóstico completo do ambiente: token CLI, Core acessível,
421
- schema do `neetru.config.json`, valor de `NEETRU_ENV`, e versão do CLI
422
- comparada com a `latest` no npm. Saída em tabela colorida (default) ou
423
- JSON (`--json`). Diferença pra `validate`: doctor inclui environment +
424
- version mismatch (warning, não fail).
425
- - `neetru upgrade` verifica `dist-tags.latest` em
426
- `https://registry.npmjs.org/@neetru/cli` e exibe instrução de upgrade
427
- (`npm install -g @neetru/cli@latest`). Sem auto-installnão quebra
428
- pipelines pinados.
429
- - `neetru autocomplete <bash|zsh|pwsh>` — gera script de shell completion
430
- pra os 22 subcomandos top-level. Usuário cola na config do shell:
431
- `neetru autocomplete bash >> ~/.bashrc`.
432
- - `neetru config set telemetry.enabled <true|false>` — opt-in explícito de
433
- telemetria. Default desligado. Quando ligado, CLI envia eventos
434
- anonimizados pra `POST /sdk/v1/telemetry/log` (placeholder na v2.0).
435
- Nunca envia tokens, paths absolutos ou conteúdo de arquivos.
436
-
437
- ### Bumped
438
-
439
- - `1.4.0 → 2.0.0` (major bump por convenção de estabilidade — sem breaking
440
- changes funcionais).
441
-
442
- ### Não publicado no npm ainda
443
-
444
- Bump local. Publish manual pra npm fica deferido owner aprovará. Build
445
- local (`npm run build` em `cli/`) gera o `dist/` pronto pra publicação.
446
-
447
- ## [1.3.0] 2026-05-06
448
-
449
- ### Adicionado
450
-
451
- - `neetru add <feature>` — copia template em `cli/templates/{feature}/*` para
452
- `src/lib/neetru/{feature}/*` no projeto atual. Features: `auth`, `billing`,
453
- `usage`, `users`, `support`. Suporta `--force` pra sobrescrever.
454
- - `neetru mocks reset` — reseta `.neetru/dev-fixtures.json` para `{}` (útil
455
- com `NEETRU_ENV=dev`).
456
- - `neetru env switch <dev|workspace|production>` — atualiza/insere
457
- `NEETRU_ENV=<value>` em `.env.local` preservando as outras chaves.
458
- - `neetru logs` ganhou flags:
459
- - `--product <productId>` filtra logs por produto.
460
- - `--channel <channel>` — filtra por channel (stdout/stderr/app/...).
461
- - `--correlation-id <uuid>` filtra por correlation ID.
462
-
463
- ### Templates novos (`cli/templates/`)
464
-
465
- - `auth/sign-in.tsx`, `auth/callback.ts`
466
- - `billing/page.tsx`, `billing/checkout.ts`
467
- - `usage/track.ts`
468
- - `users/profile.tsx`
469
- - `support/ticket-form.tsx`
470
-
471
- ### Não publicado no npm ainda
472
-
473
- Bump local `1.2.0 1.3.0`. Publish pra npm fica deferido — owner aprovará
474
- manualmente quando quiser. Build local (`npm run build` em `cli/`) já compila.
475
-
476
- ## [1.2.0] — 2026-05-06
477
-
478
- **Consolidação das duas linhas paralelas.** Esta versão unifica os comandos das duas linhas de CLI que estavam coexistindo:
479
-
480
- - **`@neetru/cli@1.0.x` (publicada no npm)**: linha *workspace-centric* com `init`, `add`, `validate`, `generate-types`, `whoami`, `login`, `status`, `logs`, `deploy`, `open`. APIs: `/api/v1/cli/workspace/*`.
481
- - **`@neetru/cli@0.1.0` (monorepo, não publicada)**: linha *server-centric* com `ai`, `init`, `config`, `login`, `logout`, `whoami`, `build`, `deploy`, `publish`. APIs: `/api/v1/cli/{catalog,deploy,servers}`.
482
-
483
- As duas falam **APIs distintas e complementares** do mesmo Neetru Core, refletindo a topologia real do produto:
484
-
485
- ```
486
- Workspace (prototipação) ──build/promote──► Server VM ou Cloud Run (produção)
487
- ```
488
-
489
- A `1.2.0` traz ambos os conjuntos de comandos numa única CLI. O monorepo passa a ser a fonte canônica.
490
-
491
- ### Adicionado em relação a `1.0.1`
492
-
493
- Comandos da linha *server-centric* (deploy via VM agent ou Cloud Run):
494
-
495
- - `neetru ai` REPL multi-model (Claude/OpenAI/Gemini) com contexto Neetru-aware
496
- - `neetru build` — empacota produto local em tarball + manifest com sha256, detecção automática de stack (node/docker/php-apache/static)
497
- - `neetru deploy` pipeline E2E interativo (escolha de produto/server/domain/port + polling status até estado terminal). Suporta `--non-interactive` para CI.
498
- - `neetru publish` — registra produto no catálogo público (`public_products`), com `--draft` e `--unpublish`
499
- - `neetru config {set|get|path}` — gerenciamento de chaves de API e config local
500
- - `neetru logout` limpa credenciais
501
- - `neetru login --token nrt_<keyId>_<secret>` — modo CI/legacy paralelo ao Device Code OAuth
502
- - `neetru login --json` — saída machine-readable para scripts
503
-
504
- ### Mantido de `1.0.1` (re-implementado em TypeScript com convenções do monorepo)
505
-
506
- - `neetru status --client-id <id>` — status de workspace (build/deploy último, domínio, tier, expira em N dias)
507
- - `neetru logs --client-id <id>` visualiza logs do workspace; suporta `-f` follow + `-n N` lines + `--since 30m` + `--level error`
508
- - `neetru validate` — health-check da config local + ping `/api/health` + whoami
509
- - `neetru open [target]` — abre dashboard, builds, logs, workspaces, products, servers, incidents no browser
510
- - `neetru init <name>` agora gera projeto Next.js 15 OU Node API (Fastify) com schema canônico v2
511
-
512
- ### Backlog 1.3.x
513
-
514
- Comandos que ainda dependem de design/templates novos:
515
-
516
- - `neetru add <feature>`scaffolds OAuth/billing/usage/users
517
- - `neetru generate-types` — codegen TypeScript de planos/features/entitlements
518
-
519
- ### Alterado
520
-
521
- - Package agora é ESM nativo (`"type": "module"`). Imports usam `.js` extension.
522
- - `neetru login` agora usa Device Code OAuth (RFC 8628) por default; `--token` permanece para CI.
523
-
524
- ### Migração de `1.0.x`
525
-
526
- Não caminho 100% automático porque a config local muda:
527
-
528
- - `1.0.x` lia `neetru.json` workspace-local com `{clientId, coreUrl}` + var de ambiente `NEETRU_CLIENT_SECRET`
529
- - `1.2.0` lê `~/.config/neetru-cli/auth.json` (Bearer token salvo por `neetru login`) + `neetru.config.json` por projeto com `{slug, runtime, publish}`
530
-
531
- Recomendação:
532
-
533
- 1. `npm uninstall -g @neetru/cli && npm install -g @neetru/cli@1.2.0`
534
- 2. `neetru login` (Device Code) — gera credencial Bearer no novo formato
535
- 3. Para comandos workspace (`status`, `logs`, `open`), passe `--client-id <oauthClientId>` explicitamente — o `clientId` continua sendo o `oauthClientId` do seu workspace, achável em UI Core `/workspaces/{id}`
536
-
537
- ## [1.0.1] — anterior
538
-
539
- Linha workspace publicada no npm. Comandos: `init`, `add`, `validate`, `generate-types`, `whoami`, `login`, `status`, `logs`, `deploy`, `open`. APIs: `/api/v1/cli/workspace/*`.
540
-
541
- ## [1.0.0] — anterior
542
-
543
- Primeira versão pública.
544
-
545
- ## [0.1.0] — interno (não publicado)
546
-
547
- Snapshot interno do monorepo durante desenvolvimento da Sprint 1+. Substituído por `1.2.0`.
1
+ # Changelog @neetru/cli
2
+
3
+ Convenção: [Keep a Changelog](https://keepachangelog.com/) + [SemVer](https://semver.org/).
4
+
5
+ ## [2.11.4] — 2026-06-05 (db init serverId p/ engines vm-* · README/help fixes)
6
+
7
+ > Patch consolidando a branch `feat/cli-2.10.2-2.11` com `main` (que havia avançado pra 2.11.3 com `deployments get|status` + `--stack=nextjs→node`). Sem breaking change.
8
+
9
+ ### Corrigido
10
+
11
+ - **`neetru db init` coleta `serverId` p/ engines vm-\*** (`bug_062f7fea`, pdv-agiliza) — o Core exige `serverId` p/ engines vm-* (e `nosql-vm`), mas o fluxo dev-facing `db init` não enviava nem expunha a flag `register_failed`. Agora aceita `--server-id <id>`; sem ele em modo interativo abre prompt listando VM hosts (`GET /api/cli/v1/servers?capacity=true&db=true`, filtra status mortos) com fallback de input livre; em modo `--yes`/`--json` falha com erro `server_id_required` claro. `serverId` vai no top-level do payload de `POST /api/cli/v1/db/register`.
12
+
13
+ ### Documentação / ajuda
14
+
15
+ - **README — comandos `db` deprecados corrigidos** (CLI-QW-7a) — a tabela ensinava `neetru db create`/`neetru db engines` (inexistentes na árvore `db`). O canônico é `neetru admin database create/engines`; nomes de engine reais (`cloud-sql-postgres`, `vm-postgres-single`, `nosql-vm`, …) em vez de `postgres`/`mysql`.
16
+ - **`ops heartbeat` / `ops smoke observability` defaults mágicos surfados** (CLI-QW-8) `--server-id=srv-test-01` (placeholder de teste) e `--base-url=https://core.neetru.com` agora aparecem na descrição do comando + no help da option, evitando sondar silenciosamente um server inexistente.
17
+ - **README drift de stack corrigido** (CLI-QW-7b)alinhado ao `package.json` real: Node `>=20` (era `>=22`), Commander 12 (era 11), Inquirer 10 (era 12). Nenhuma dep nem `engines` foi tocado só doc.
18
+
19
+ ## [2.11.0] — 2026-05-27 (hardening: token unificado · URL allowlist · telemetry real)
20
+
21
+ > Minor de hardening pós-2.10.2. Fecha 3 itens HIGH levantados na review do chefe-de-CLI (`docs/_review/CHEFE_CLI_REVIEW_2026-05-27.md` no Core) + Codex sweep (HIGH-10). Nenhuma breaking change — comandos e flags antigas seguem funcionando; warnings apontam para a deprecação prevista pra 2.12.0.
22
+
23
+ ### Adicionado
24
+
25
+ - **`--allow-untrusted-url` em `neetru config set`** (MASTER-HIGH-049) — flag opt-in pra setar `neetruApiUrl` fora da allowlist canônica. Sem essa flag (ou `NEETRU_ALLOW_UNTRUSTED_URL=1`) o `config set` rejeita com exit(1) + banner vermelho. Allowlist: `api.neetru.com`, `core.neetru.com`, `neetru.com` (apex), `*.neetru.com` (subdomínios), `localhost`/`127.0.0.1`/`::1` (dev HTTP ok); demais hosts exigem HTTPS.
26
+ - **Telemetry real** (MASTER-HIGH-052) `telemetry.enabled` deixou de ser flag fantasma. Quando opt-in, `neetru <comando>` agora emite evento anônimo (`{command, durationMs, ok, exitCode, ts}`) para `POST /api/sdk/v1/telemetry/log`. Identificação por `installId` UUID em `~/.config/neetru-cli/install-id` (chmod 0600). Nunca envia token, path absoluto, email, ou env. Buffer in-memory cap 50 + flush em `beforeExit` com timeout 1.5s (fire-and-forget erro de rede não bloqueia o comando). Override: `NEETRU_TELEMETRY_DISABLED=1`.
27
+
28
+ ### Mudado (compat-friendly)
29
+
30
+ - **Token resolver unificado** (MASTER-HIGH-048) — `api-client.ts` (`apiRequest` + `apiStream`) agora lê o Bearer token via `getActiveTokenSync()` (`src/lib/token-resolver.ts`), que prefere `~/.config/neetru-cli/auth.json` (canônico desde Sprint 1) sobre o Conf storage (legacy). Quando o token vem do Conf, emite warning one-shot stderr alertando deprecação pra 2.12.0. 8 comandos que liam `config.get('neetruApiKey')` direto (`status`, `validate`, `deploy`, `vm`, `logs`, `doctor`, `publish`, `whoami`) migrados pra `getActiveTokenSync()`. Comportamento anterior — "logado pra `whoami` mas não pra `status`" quando o token só existia em `auth.json` — desaparece.
31
+ - **`neetru config set neetruApiKey` emite deprecation warning** o setter manual continua funcionando, mas avisa que `neetru login` é o caminho canônico (que grava em `auth.json` chmod 0600). Storage Conf de `neetruApiKey` será removido em 2.12.0.
32
+ - **`apiRequest` emite warning one-shot quando host customizado fora da allowlist** defesa em profundidade pra casos em que o owner tem URL untrusted em Conf (não pegou o `config set` 2.11).
33
+
34
+ ### Infraestrutura de testes (+34 tests)
35
+
36
+ - **Novo `src/__tests__/url-allowlist.test.ts`** (15 cases): hosts trusted + edge cases (domain confusion `neetru.com.evil.com`, HTTP em prod, protocolos não suportados).
37
+ - **Novo `src/__tests__/config-set-allowlist.test.ts`** (7 cases): rejeita default, aceita com `--allow-untrusted-url`, aceita com env override.
38
+ - **Novo `src/__tests__/token-resolver.test.ts`** (4 cases): precedência `auth.json > Conf > null` + warning one-shot stderr.
39
+ - **Novo `src/__tests__/telemetry.test.ts`** (8 cases): opt-in default off + env override, happy path POST com payload validado, idempotência do flush, falha de rede engolida, cap de buffer, privacy (zero token/path/email no payload).
40
+ - 7 tests existentes ganharam `readAuthJsonSync: vi.fn(() => null)` no mock de `auth.js` (control-plane, workspaces, products-create, sdk-credential, new-browser-optin, doctor, publish) — preserva semântica antiga de "token via config.set" caindo no fallback Conf.
41
+ - `vitest.config.ts` seta `NEETRU_SUPPRESS_LEGACY_WARNINGS=1` em test setup pra não poluir CI com banner de deprecation.
42
+
43
+ ### Deprecation timeline
44
+
45
+ - **2.11.0 (esta release):** Conf `neetruApiKey` ainda funciona (com warning); login grava em ambos os storages.
46
+ - **2.12.0 (planejado):** `login` para de gravar em Conf; `config set neetruApiKey` continua aceito mas vira no-op com warning; `Conf neetruApiKey` removido do schema. Owner que copia binário pra outra máquina precisa garantir migração `~/.config/neetru-cli/auth.json`.
47
+
48
+ ### Sem breaking change
49
+
50
+ - Todos os comandos e flags da 2.10.x seguem funcionando.
51
+ - Endpoints API canônicos inalterados.
52
+ - Path padrão `~/.config/neetru-cli/auth.json` continua canônico.
53
+
54
+ ---
55
+
56
+ ## [2.10.2] — 2026-05-27 (patch: paths broken em produção + autocomplete drift)
57
+
58
+ > Patch urgente — chefe-de-CLI review do dia (`docs/_review/CHEFE_CLI_REVIEW_2026-05-27.md` no Core) + `MASTER_PLAN_2026-05-27.md` §4 Bloco G. Quatro endpoints quebrados em produção (404 silencioso ou rota inexistente) + cobertura de autocomplete em ~45% silenciosamente. Sem nada novo de UI ou behavior — só fix de quem já estava 404'eando.
59
+
60
+ ### Corrigido (CRITICAL)
61
+
62
+ - **MASTER-CRIT-035 — `neetru promote` apontava pra endpoint inexistente.** `src/commands/promote.ts:104` chamava `/cli/v1/promotion/request` (sem prefixo `/api`) → 404 sempre. Pior: o handler de 404 ainda mascarava o erro com "Endpoint ainda não disponível, entra em build no Sprint 11" — a rota existe há sprints sob `/api/cli/v1/promotion/request`. Fixado. Handler de 404 agora reporta erro real (exit 5). Test cúmplice `promote.test.ts:110` atualizado (pinava `/cli/v1/...` como correto).
63
+ - **MASTER-CRIT-036 — `neetru agent release` apontava pra endpoint inexistente.** `src/commands/agent-release.ts:215` chamava `/cli/v1/agent/release`. Trocado pra canônico `/api/cli/v1/agent/release`.
64
+ - **MASTER-CRIT-037 `neetru fn deploy` removido (rota nunca existiu).** `src/commands/fn.ts` apontava pra `/cli/v1/fn/deploy` não rota em `/api/**/fn/**` no Core. Comando deletado por inteiro (arquivo + import em `src/index.ts` + entry em autocomplete + test cúmplice `src/__tests__/fn.test.ts` que pinava o path errado). Reintroduzir quando/se a feature for de fato implementada server-side.
65
+
66
+ ### Corrigido (HIGH)
67
+
68
+ - **MASTER-HIGH-050 — `neetru logs` apontava pra alias legacy.** `src/commands/logs.ts:106` usava `/api/v1/cli/logs` (inversão dos prefixos). O alias legacy ainda existe no Core mas tem deprecation prevista para 2026-07-01 depois disso `neetru logs` morre sem aviso. Trocado pra canônico `/api/cli/v1/logs`.
69
+ - **MASTER-HIGH-051 — autocomplete cobria só ~45% dos comandos.** `TOP_LEVEL_COMMANDS` em `src/commands/autocomplete.ts` listava 22 entries de um total de ~50 comandos top-level expostos em `src/index.ts`. Bash/zsh/pwsh completion silenciosamente broken para a maioria das operações (auth, admin, customers, tenants, audit, billing, servers, workspaces, deployments, cloud-run, api-catalog, products, vm, support, bug, dns, hosting, builds, dr, docs, …). Reescrito para incluir TODOS os ≈50 comandos, em ordem alfabética. Aliases incluídos (`menu` → `ui`, `ar` → `artifact-registry`).
70
+
71
+ ### Infraestrutura de testes (regression guards)
72
+
73
+ - **Novo: `src/__tests__/endpoint-paths.regression.test.ts`** varre `src/commands/**/*.ts` extraindo o primeiro argumento de toda chamada `apiRequest(...)` / `apiStream(...)` e valida que começa com prefixo canônico: `/api/cli/v1/`, `/api/sdk/v1/`, `/api/v1/`, ou `/api/internal/`. Allowlist explícita pra `/api/health` (Cloud Run healthcheck). Três testes: prefixo canônico, zero `/cli/v1/*` cru (vetor dos CRIT-035..037), zero `/api/v1/cli/*` invertido (vetor do HIGH-050).
74
+ - **Novo: `src/__tests__/top-level-commands-coverage.regression.test.ts`** — parse simples de `src/index.ts` extraindo `program.command('X')`; exige cobertura ≥95% em `TOP_LEVEL_COMMANDS` + zero entries fantasma + ordem alfabética. Detecta drift do autocomplete quando alguém adicionar/remover comando no `index.ts` no futuro.
75
+
76
+ ### Sem mudança
77
+
78
+ - Comportamento do CLI fora dos 4 fixesidêntico ao 2.10.1.
79
+
80
+ ---
81
+
82
+ ## [2.10.0] — 2026-05-27 (rename: `neetru marketplace` → `neetru archive` · fonte agora pública)
83
+
84
+ ### BREAKING
85
+
86
+ - **`neetru marketplace` foi renomeado para `neetru archive`.** Subcomandos preservados (`skills install/update/list/uninstall`, `sdk init/templates/add`, `browse`). NÃO há alias de retrocompat — o comando antigo deixa de existir nesta versão. Quem rodava `neetru marketplace skills install` em scripts CI precisa trocar para `neetru archive skills install`.
87
+ - **Cache local mudou de `~/.neetru/marketplace-cache/` para `~/.neetru/archive-cache/`.** Caches antigos podem ser apagados manualmente (não há migração automática — `archive skills install` cria o novo limpo). A função `getSkillsSourceDir` mantém retrocompat detectando o nível `claude-skills/` caso o cache de uma versão anterior do `archive-cache` ainda tenha esse layout.
88
+ - **Variável de ambiente `NEETRU_MARKETPLACE_SYMLINK` virou `NEETRU_ARCHIVE_SYMLINK`** (Windows). Quem usava precisa renomear.
89
+
90
+ ### Mudado
91
+
92
+ - **Fonte de skills migrou de `github.com/Neetru/neetru-libs` (privado) para `github.com/Neetru/neetru-libs-public` (público).** O `neetru-libs` privado mantém `packages/` (`@neetru/db-classifier`, `sql-guard`, `pii-mask`, `neetru-glossario`) — só `claude-skills/` foi exposto, via `git subtree push --prefix=claude-skills`. Resultado: `neetru archive skills install` deixa de exigir `gh auth setup-git` ou `GITHUB_TOKEN` — clone anônimo funciona.
93
+ - **Layout do clone público é mais flat:** `plugins/<plugin>/skills/<skill>/SKILL.md` no topo (em vez de `claude-skills/plugins/...`). O resolver detecta o layout legado automaticamente — caches antigos continuam resolvendo até o próximo `archive skills update`.
94
+
95
+ ### Por quê
96
+
97
+ - O 2.9.13 quebrava em `git clone` quando `neetru-libs` virou privado (HTTP 401 sem credencial git configurada). O fix arquitetural certo era separar o catálogo público de skills do código proprietário em `packages/` — `neetru-libs-public` é esse catálogo. A renomeação `marketplace → archive` aproveitou o break pra alinhar o nome do comando ao conceito real (catálogo/arquivo de artefatos, não um marketplace transacional).
98
+
99
+ ## [2.9.13] — 2026-05-26 (feat: force-cleanup recovery + mfa-status observability)
100
+
101
+ ### Adicionado
102
+
103
+ - **`neetru servers force-cleanup <serverId> --reason "..." [--yes] [--json]`** recovery quando VM stuck (status=timeout_agent_register/falha_provisionamento/provisionando >30min) e flow normal (`deactivate`/`delete` com MFA) não funciona. NÃO exige MFA (bypass intencional pra desbloquear deadlock bug_c42fa12b CRITICAL quando MFA broken via bug_84e4dacb). Double-confirm interativo: usuário digita o serverId. Audit pesado + notification all staff garantem accountability. Bate em POST `/api/cli/v1/servers/[id]/force-cleanup`.
104
+ - **`neetru auth mfa-status [--json]`** observability MFA do usuário atual: enrolled, enrolledAt, lastUsedAt, hasEncryptedSecret, recoveryCodesCount, hint acionável (clock skew vs nunca usado vs zero recovery codes vs MFA não enrolled). Bate em GET `/api/cli/v1/auth/mfa/status`. Útil quando `servers deactivate` rejeita TOTP e owner precisa debugar antes de tentar novamente.
105
+
106
+ ### Corrige (HIGH/CRITICAL)
107
+
108
+ - **bug_c42fa12b1e194a0794f14ea74994e2a3 (CRITICAL)Deadlock VM stuck + MFA broken.** force-cleanup destrava recovery sem precisar MFA. Pré-condições rígidas + audit pesado mitigam risco de uso indevido.
109
+ - **bug_84e4dacbcaf14ea09ae9825ff2e2b9f3 (HIGH) — MFA TOTP rejeita opaco.** mfa-status mostra `lastUsedAt=null` indicando "MFA enrolled mas nunca usou com sucesso" + sugere causas comuns (clock skew, secret desync).
110
+
111
+ ## [2.9.12] — 2026-05-26 (fix: libuv crash MFA error path + lint guard process.exit)
112
+
113
+ ### Corrigido (MEDIUM — regressão libuv em MFA)
114
+
115
+ - **bug_6362578edfd7498dbcfe59853181be20 (MEDIUM) `Assertion failed: !(handle->flags & UV_HANDLE_CLOSING)` voltou em CLI 2.9.9 em error path do MFA.**
116
+ Reprodução: `neetru servers deactivate <id> --yes --mfa-token=<code> --json` quando o servidor retorna 403 (código MFA inválido ou expirado).
117
+ Causa raiz: o fix anterior (bug_818cf6d, 2.9.9) cobriu apenas `build.ts`. Os outros error paths — `handleApiError` em `cli-read.ts`, `resolveStepUp` em `cli-write.ts`, `failLookup`/`failInput` em `pickers.ts`, e todos os ~200 pontos de `process.exit()` em 46 arquivos de comando — continuavam chamando `process.exit()` direto após I/O async (fetch 403, inquirer prompts, readline MFA). Em Windows o libuv assertion é fatal.
118
+ Fix: sweep completo46 arquivos de comando + 4 arquivos de lib (`cli-read`, `cli-write`, `pickers`, `iam-preflight`) convertidos para `safeExit(N)`.
119
+
120
+ ### Infraestrutura de testes (guard antirregressão)
121
+
122
+ - **Novo teste `src/__tests__/regressions/no-direct-process-exit.regression.test.ts`** — varre `src/commands/**/*.ts` e `src/lib/**/*.ts` e FALHA se encontrar qualquer `process.exit(` direto. Detecta regressões desta classe automaticamente em CI. Arquivos isentos: `utils/safe-exit.ts` (a implementação em si). Adição de `// safe-exit-exempt: <razão>` numa linha permite marcar exits síncronos intencionais sem quebrar o guard.
123
+
124
+ ## [2.9.9]2026-05-25 (fix: libuv crash Windows + npm ci file lock)
125
+
126
+ ### Corrigido (2 MEDIUM Windows compat)
127
+
128
+ - **bug_818cf6d507b94c81a23b205eb9d18d71 (MEDIUM) — CLI crashava com `Assertion failed: !(handle->flags & UV_HANDLE_CLOSING)` em Windows.**
129
+ Causa raiz: handles libuv (http keep-alive, stdin/stdout, ora spinner setInterval) ficavam em `UV_HANDLE_CLOSING` quando `process.exit(1)` matava o loop bruscamente. Em Linux/Mac libuv só warna; em Windows é assertion fatal.
130
+ Fix: novo `src/utils/safe-exit.ts` com `safeExit(code): never` que faz cleanup explícito antes do exit (stopAllSpinners + destroy stdin + destroy http/https globalAgent). Build agora usa `safeExit(1)` em vez de `process.exit(1)` no catch. Spinners registrados via `registerSpinner()` (novo `src/utils/spinner-registry.ts`) pra cleanup centralizado.
131
+
132
+ - **bug_93f984a16ad64656af2230583b7e554f (MEDIUM) `neetru build` quebrava com EPERM unlink quando `next dev` rodando em paralelo.**
133
+ Causa raiz: `npm ci` deletava `node_modules/@next/swc-*` que o dev server tinha aberto em file lock no Windows.
134
+ Fix: trocado `npm ci` por `npm install --no-save --no-audit --no-fund` (respeita locks parciais). Nova flag `--no-install` permite skip total quando o dev sabe que `node_modules` está pronto. Warn explícito em Windows orientando pausar dev server.
135
+
136
+ ### Novidades técnicas
137
+
138
+ - **`src/utils/safe-exit.ts`** `safeExit(code): never` + `setSafeExitCode(code): void` com cleanup robusto de handles libuv.
139
+ - **`src/utils/spinner-registry.ts`** registry global de spinners ora pra cleanup centralizado em error paths.
140
+ - **`neetru build --no-install`** pula `npm install` (assume `node_modules` pronto).
141
+
142
+ ### Testes
143
+
144
+ - `src/__tests__/safe-exit.test.ts` 9 testes novos (spinner-registry: 6, safeExit: 3).
145
+
146
+ ## [2.9.7] — 2026-05-25 (fix: URI Artifact Registry completa + Cloud Build remoto + Dockerfile template — 3 CRITICAL/HIGH bugs deploy cloud-run)
147
+
148
+ ### Corrigido (CRITICAL/HIGH deploy cloud-run bloqueado para gestovendas)
149
+
150
+ - **bug_467db337ea9749a4b85d270d4e10576f (CRITICAL)`neetru deploy` gerava URI Artifact Registry malformada.**
151
+ URI original: `us-central1-docker.pkg.dev/gestovendas:tag` (só 2 segmentos inválida).
152
+ URI correta: `us-central1-docker.pkg.dev/{project}/{repo}/{image}:{tag}` (4 segmentos obrigatórios do AR).
153
+ Fix: `buildArtifactRegistryUri` resolve o project via `gcloud config get-value project` quando o
154
+ `--registry` passado contém apenas o host. O repo é inferido como `{slug}-{env}` ou explicitado via
155
+ `--registry-repo`. Quando `--registry` contém `host/project/repo` (3 segmentos), é usado diretamente.
156
+ Suporta 3 formatos de `--registry`:
157
+ - Host apenas: `us-central1-docker.pkg.dev` descobre project via gcloud config.
158
+ - Host + project: `us-central1-docker.pkg.dev/neetru` infere repo.
159
+ - Host + project + repo: `us-central1-docker.pkg.dev/neetru/gestovendas-staging` usa direto.
160
+
161
+ - **bug_0a551e02295b42b9894f6eb6b13887b3 (CRITICAL) — `neetru deploy --target=cloud-run` exigia docker local.**
162
+ Docker Desktop não é viável em Windows dev machine (5+ GB, requer WSL2, reboot) nem em CI headless.
163
+ Fix: pipeline substituído por `gcloud builds submit --tag=<uri> [--project=<id>] <cwd>` (Cloud Build
164
+ remoto). Não exige Docker instalado apenas `gcloud` autenticado (já feito via `neetru bootstrap`).
165
+ `--build-local` força o comportamento anterior (docker build + push) para devs que preferem build local.
166
+
167
+ - **bug_1904ba55feeb480690eb8a7f00b4a7b7 (HIGH) `--stack=node` sem Dockerfile terminava com erro pouco acionável.**
168
+ Fix: quando `--stack=node` ou `--stack=nextjs` e não `Dockerfile` no projeto, o CLI gera
169
+ automaticamente um template adequado no `cwd` antes de chamar o Cloud Build, e apaga ao terminar.
170
+ Templates:
171
+ - `node`: `FROM node:22-slim` + `npm ci --omit=dev` + `CMD ["node", "server.js"]` + porta 8080.
172
+ - `nextjs`: multi-stage com standalone output + `COPY .next/standalone` + porta 8080.
173
+ - `docker`: continua exigindo Dockerfile manual (com mensagem de erro clara).
174
+ Aviso `log.warn` antes de gerar o template para o dev saber o que aconteceu.
175
+
176
+ ### Adicionado
177
+
178
+ - **`--registry-repo <name>`** — flag opcional para especificar o nome do repositório AR explicitamente.
179
+ Se omitido, inferido como `{productSlug}-{env}` (ex: `gestovendas-staging`).
180
+ - **`--build-local`**força `docker build` local em vez do Cloud Build remoto.
181
+ - **`--stack=nextjs`** novo valor suportado em `neetru deploy`, gera Dockerfile Next.js standalone.
182
+ - **`DeployOptions.json?: boolean`** campo para propagação de modo JSON em preflight IAM checks.
183
+
184
+ ### Testes
185
+
186
+ - `src/__tests__/deploy-image-uri.test.ts` — 10 casos cobrindo `buildArtifactRegistryUri` (segmentos, tag sanitização, REGRESSÃO original).
187
+ - `src/__tests__/deploy-cloud-build.test.ts`5 casos cobrindo Cloud Build remoto vs docker local.
188
+ - `src/__tests__/deploy-dockerfile-template.test.ts` 7 casos cobrindo geração/limpeza de template, node/nextjs/docker, warning, existente não sobrescrito.
189
+
190
+ ## [2.9.6] 2026-05-25 (fix: 3 HIGH Windows compat bug_ec17af + 0cf14fba + 6001c5e)
191
+
192
+ ### Corrigido
193
+
194
+ - **bug_ec17af083d7045a1a00f24255efb716c — `neetru deploy --target=cloud-run --artifact=<file>` rejeita silenciosamente.**
195
+ `--artifact` (tarball source) é incompatível com `target=cloud-run` que exige imagem de container OCI.
196
+ Adicionada verificação explícita em `runCloudRunDeploy`: quando `--artifact` ou `--artifact-url` é passado
197
+ com `target=cloud-run`, o CLI sai com `exit 1` e exibe mensagem orientadora com as 3 alternativas corretas:
198
+ `--image <uri>`, `--registry <host>` (build automático) e `--target=vm` (que aceita tarball).
199
+ Anteriormente a flag era silenciosamente ignorada, levando ao erro críptico "Sem imagem pra deployar".
200
+
201
+ - **bug_0cf14fba40ec4352b75f3af2467e24b0 `neetru build` quebra em Windows com scripts npm unix-only.**
202
+ Scripts como `NODE_ENV=production next build` usam sintaxe de variável de ambiente Unix incompatível
203
+ com `cmd.exe`. Adicionada função `detectsUnixEnvPrefix` em `buildNode`: quando `process.platform === 'win32'`
204
+ e o script `build` do `package.json` contém prefixo de env Unix (padrão `VAR=val ...`), o CLI emite
205
+ warning orientador antes de tentar rodar. O warning lista as 2 soluções: adicionar `cross-env` ao script,
206
+ ou remover o prefixo (Next.js já usa `production` por padrão em `next build`).
207
+ O build prossegue mesmo com o warning (shell=true no spawn já torna compatível em muitos casos).
208
+
209
+ - **bug_6001c5e83c764428ae39a5d6a1f8be82 `neetru build` falha com tar em paths com drive-letter Windows.**
210
+ GNU tar (MSYS2/Git Bash) interpreta `S:` como host SSH, causando "Cannot connect to S: resolve failed".
211
+ Correção dupla em `tarDirectory` (e `buildDocker`):
212
+ 1. `--force-local` adicionado automaticamente quando `process.platform === 'win32'`instrui o GNU tar
213
+ a não interpretar nomes de arquivo como endereços remotos (ignorado pelo bsdtar nativo do Windows 10+).
214
+ 2. `normalizePathForTar()`: converte `S:\Documents\...` `/S/Documents/...` antes de passar pro tar,
215
+ compatível com ambos os tars (GNU e BSD).
216
+ Workaround manual do usuário (`tar --force-local -czf ...`) agora está embutido automaticamente no CLI.
217
+
218
+ ## [2.9.3] — 2026-05-25 (fix HIGH: branch NoSQL no db apply — Bug 11 Fase 1)
219
+
220
+ ### Corrigido
221
+
222
+ - **Bug 11 Fase 1 — `neetru db apply` era SQL-only; branch NoSQL nunca era alcançada.**
223
+ Adicionada detecção de engine em `runDbApply`: quando `engine {nosql-vm, firestore-instance}`,
224
+ o pipeline SQL (drizzle-kit + Postgres efêmero + classify) é completamente ignorado.
225
+ A nova função `runNoSqlApply` calcula o fingerprint SHA-256 do `schema.ts` local e envia
226
+ `POST /api/cli/v1/db/apply` com `schemaDefinition: null` (Fase 1 sem JSON Schema export).
227
+ O Core registra o snapshot em `product_db_schema_snapshots/{id}` (implementado em commit `116f0d60`).
228
+ Saída interativa: spinner `"Aplicando schema NoSQL (sem rehearse engine schemaless)…"`.
229
+ Saída `--json`: `{ ok, status, engine, snapshotId, fingerprint, dryRun }`.
230
+ `--dry-run` calcula fingerprint mas não envia ao Core (status `dry_run`).
231
+ O pipeline SQL para `cloud-sql-*` e `vm-*` permanece intacto sem regressão.
232
+
233
+ ## [2.9.2] 2026-05-25 (ux: cliente padrão Neetru automático)
234
+
235
+ ### Melhorado
236
+
237
+ - **`neetru workspaces create` — `--customer` agora opcional para produtos Neetru-owned.**
238
+ Quando o produto selecionado pertence à Neetru (`ownedBy='neetru'`, `ownerTeam='Neetru Core'`
239
+ ou slug na lista conhecida), o CLI detecta via API e pula o prompt de cliente automaticamente.
240
+ Em modo interativo exibe `"Cliente omitido produto Neetru detectado. Usando cliente interno automaticamente."`.
241
+ Em modo `--json`, envia `customerId` ausente; o Core injeta o customer interno (`isNeetruInternal=true`).
242
+ Para produtos de terceiros, `--customer` continua obrigatório (erro acionável com instruções de criação).
243
+
244
+ - **`neetru tenants create` mesma lógica de auto-default.**
245
+ Prompt de `customerId` pulado automaticamente quando produto é Neetru-owned.
246
+
247
+ - **`neetru workspaces create` mensagem de confirmação no output.**
248
+ Quando `--customer` não é fornecido, exibe `"Cliente: Neetru Tecnologia (interno) auto-detectado pelo produto Neetru."`.
249
+
250
+ ## [2.9.1] — 2026-05-25 (security: 5 HIGH fixes)
251
+
252
+ ### Corrigido (segurança)
253
+
254
+ - **HIGH-1 `db apply --json` selecionava o primeiro banco silenciosamente com múltiplos bancos.**
255
+ Em modo não-interativo (`--json` ou `--yes` sem TTY), se `.neetru/db.json` tiver N > 1 bancos
256
+ e `--db` não for passado, o CLI agora emite erro estruturado em vez de aplicar no primeiro banco.
257
+ Saída JSON: `{ ok: false, error: "db_required", message: "...", available: [...] }`.
258
+ Em CI isso evitava migração silenciosa no banco errado.
259
+
260
+ - **HIGH-2 — Abertura de URL no Windows usava `cmd /c start` sem validação de protocolo.**
261
+ URLs derivadas de config podiam conter caracteres de injeção de shell (`& malicious.exe`).
262
+ Nova função `safeOpenUrl` valida `^https?://` antes de qualquer chamada de sistema e usa
263
+ `rundll32 url.dll,FileProtocolHandler` (sem shell) no Windows. Aplica em `open.ts` e
264
+ `workspaces.ts` (que agora delega para `safeOpenUrl`).
265
+
266
+ - **HIGH-3`db init` gravava stub local em `.neetru/db.json` antes de registrar no Core.**
267
+ Falha de rede/400 do Core deixava entrada órfã e re-rodar `db init` adicionava banco duplicado.
268
+ Agora o registro no Core acontece primeiro; `.neetru/db.json` só é escrito após sucesso.
269
+
270
+ - **HIGH-4 — `marketplace sdk add <template>` aceitava path traversal.**
271
+ `path.join(templatesDir, templateName)` aceitava `../../etc/passwd` como nome.
272
+ Adicionada whitelist `ALLOWED_SDK_TEMPLATES` e verificação `startsWith(resolve(templatesDir) + sep)`
273
+ como defesa em profundidade.
274
+
275
+ - **HIGH-5 `docs publish` usava path absoluto Windows como slug.**
276
+ Path como `C:/Users/dev/projeto/docs/intro.md` virava slug `C:/Users/dev/projeto/docs/intro`,
277
+ expondo estrutura de filesystem. `deriveSlugFromPath` agora converte para relativo via
278
+ `path.relative(cwd, file)` e rejeita slugs com `:`, `..` ou `/` inicial.
279
+
280
+ ## [2.8.2] 2026-05-25 (fix UX slug conflict + docs open)
281
+
282
+ ### Corrigido
283
+
284
+ - **Bug #31 — `neetru new` não falha seco em conflito de slug.**
285
+ Quando o Core retorna 400 com "Já existe um produto com o slug X", o CLI
286
+ agora exibe o produto existente (nome, ID, status) e oferece um prompt
287
+ interativo com três opções:
288
+ 1. Vincular este projeto local ao produto existente (escreve `.neetru/config.json`
289
+ apontando para o `productId`).
290
+ 2. Criar com slug diferentelista sugestões (`gestovendas-v2`, `-2`, etc.)
291
+ ou permite digitar um slug livre.
292
+ 3. Cancelar.
293
+ Removida a mensagem "Tente manualmente: neetru products create --slug <mesmo-slug>"
294
+ que sugeria repetir exatamente o comando que vai falhar de novo.
295
+ O fallback genérico cobre qualquer 400 cujo `message` contenha "Já existe",
296
+ "slug", "already exists" ou "duplicate".
297
+
298
+ - **Bug #26 `neetru docs` não abria documentação ao vivo.**
299
+ O comando `neetru docs` era exclusivamente um registry CRUD (publish/list/get/delete)
300
+ e não tinha forma de acessar a documentação pública. Adicionado:
301
+ - `neetru docs open [topic]` — abre `https://core.neetru.com/docs` (ou seção
302
+ específica) no browser padrão. Tópicos: `sdk`, `cli`, `db`, `webhooks`, `auth`,
303
+ `billing`, `observability`, `infra`, `dns`, `deploy`, `architecture`.
304
+ - `neetru docs open` sem argumento — abre o índice geral.
305
+ - Argumentos desconhecidos abrem busca: `core.neetru.com/docs?q=<query>`.
306
+ - No menu interativo (`neetru ui`), "Docs live" agora exibe "Abrir documentação
307
+ no navegador" como primeira opção antes das opções de registry.
308
+
309
+ ### Notas de uso
310
+
311
+ ```
312
+ neetru docs open # abre core.neetru.com/docs
313
+ neetru docs open sdk # vai direto pra referência do SDK
314
+ neetru docs open webhooks # manual de runtime/webhooks
315
+ ```
316
+
317
+ ## [2.8.1] 2026-05-25 (marketplace)
318
+
319
+ ### Adicionado
320
+
321
+ - **`neetru marketplace`** central de artefatos do ecossistema Neetru.
322
+ - `neetru marketplace skills install` — clona `Neetru/neetru-libs` em
323
+ `~/.neetru/marketplace-cache/` e instala skills em `~/.claude/skills/`.
324
+ Linux/macOS: symlink (atualizações automáticas via git pull).
325
+ Windows: cópia recursiva (sem exigir Developer Mode).
326
+ - `neetru marketplace skills update` — git pull no cache + re-copia skills
327
+ instaladas como cópia (symlinks são atualizados pelo pull).
328
+ - `neetru marketplace skills list` — tabela com nome, versão, status e
329
+ descrição de cada skill disponível no cache local.
330
+ - `neetru marketplace skills uninstall` — remove skills de `~/.claude/skills/`
331
+ com confirmação interativa (bypass via `--yes`).
332
+ - `neetru marketplace sdk init` adiciona `@neetru/sdk@^2.1.0` ao
333
+ `package.json` do projeto atual e cria `src/neetru.ts` com boilerplate
334
+ de `createNeetruClient`. Idempotente — não sobrescreve arquivo existente.
335
+ - `neetru marketplace sdk templates` — lista templates disponíveis em
336
+ `templates/` da instalação do CLI.
337
+ - `neetru marketplace sdk add <template>` copia template de feature
338
+ (auth/billing/usage/support/users) pra `src/` do projeto atual.
339
+ - `neetru marketplace browse` abre `https://github.com/Neetru/neetru-libs`
340
+ no browser (start/open/xdg-open por plataforma).
341
+ - **Menu interativo** item **"Marketplace"** adicionado ao menu principal
342
+ (entre Suporte e Docs live) com sub-menu completo: skills (instalar /
343
+ atualizar / listar / remover) + SDK (init / add template / listar / docs)
344
+ + abrir no GitHub.
345
+
346
+ ## [2.7.5] — 2026-05-20 (fix do crash no upgrade)
347
+
348
+ ### Corrigido
349
+
350
+ - `neetru upgrade` não crasha mais ao terminar. O comando chamava
351
+ `process.exit(0)` logo após o `fetch` ao npm no Windows isso
352
+ derrubava o libuv com `Assertion failed: !(handle->flags &
353
+ UV_HANDLE_CLOSING)` (`async.c`), porque o socket do undici (fetch
354
+ nativo) ainda estava em teardown. Agora o comando só retorna; o event
355
+ loop drena sozinho (o undici dá unref nos sockets idle) e o processo
356
+ encerra limpo na hora.
357
+
358
+ ## [2.7.4] 2026-05-20 (submenus redesenhados)
359
+
360
+ ### Adicionado
361
+
362
+ - Submenu **"Começar um projeto"** no menu principal reúne o scaffold
363
+ local (`neetru init`), a criação completa (`neetru new`) e uma tela de
364
+ info sobre o `@neetru/sdk` (o que é, como instalar e consumir).
365
+ - Os 10 submenus ganharam o **mesmo visual do menu principal**: moldura
366
+ azul-marinho, marcador `> <` no item ativo e navegação por setas — em
367
+ coluna única, alinhada à esquerda.
368
+
369
+ ### Corrigido
370
+
371
+ - Submenu não engole mais a primeira seta. O menu principal entregava o
372
+ stdin pausado / fora de raw mode pro submenu, e o inquirer perdia a
373
+ 1ª tecla — só respondia depois de um toque inicial. Agora o stdin fica
374
+ "quente" na entrega; a seta funciona de cara.
375
+
376
+ ## [2.7.3] 2026-05-20 (polish do cabeçalho)
377
+
378
+ ### Mudado
379
+
380
+ - Cabeçalho do `neetru` interativo: logo renderizado **ao lado** do texto
381
+ (antes era acima), com a sessão e a versão alinhadas à direita do logo.
382
+ - Paleta de contorno do menu e do logo ajustada para um azul mais suave.
383
+
384
+ ## [2.7.2] — 2026-05-20 (aviso de versão + menu em 2 colunas)
385
+
386
+ ### Adicionado
387
+
388
+ - O cabeçalho do `neetru` interativo mostra a **versão instalada** (`v2.7.2`)
389
+ ao lado do usuário logado. Quando uma versão mais nova publicada no
390
+ npm, aparece uma linha **amarela** avisando pra rodar `neetru upgrade`.
391
+ A checagem tem timeout curto e é à prova de falha — offline não trava o
392
+ CLI.
393
+ - Menu principal redesenhado em **duas colunas**, com navegação por setas
394
+ (↑/↓/←/→) e contorno azul-marinho; o item ativo é marcado com `> <`.
395
+
396
+ ## [2.7.1] 2026-05-20 (UI do CLI interativo)
397
+
398
+ ### Adicionado
399
+
400
+ - Logo Neetru em ANSI truecolor no cabeçalho do `neetru` interativo.
401
+ - Cabeçalho mostra o usuário logado (email), lido localmente do
402
+ `auth.json` — sem chamada de rede.
403
+ - Menu principal com o nome do recurso + uma descrição curta abaixo,
404
+ quando útil.
405
+
406
+ ### Corrigido
407
+
408
+ - O CLI interativo não encerra mais sozinho: comandos que chamavam
409
+ `process.exit()` em erro (ex.: "Nenhum server encontrado") matavam o
410
+ menu inteiro. Agora o erro é capturado e o CLI volta ao menu — só
411
+ "Sair" (ou Ctrl+C) encerra.
412
+
413
+ ## [2.7.0] 2026-05-20 (Fluxo de Ambientes Fase 3 destino cloud-run)
414
+
415
+ ### Adicionado
416
+
417
+ - `neetru deploy --target=cloud-run` — caminho de deploy pro destino Cloud Run
418
+ dedicado. Aceita `--image <uri>` (imagem de container já buildada e pushada)
419
+ ou faz `docker build` + `docker push` automático via `--registry <host>`
420
+ (Artifact Registry). O destino `cloud-run` agora aparece no menu interativo.
421
+
422
+ ### Mudado
423
+
424
+ - `neetru promote` vocabulário de estágios migrado para `dev | staging | prod`
425
+ (antes `dev/workspace/beta/prod`). Gates: 24h em `dev→staging`,
426
+ 168h + canary em `staging→prod`.
427
+ - `neetru deploy --target`sem valor default; omitir abre o menu interativo
428
+ (workspace / cloud-run / vm). Modo não-interativo continua assumindo `vm`.
429
+
430
+ ## [2.0.0] 2026-05-06 (Sprint 12 CLI estabilizada)
431
+
432
+ ### Adicionado
433
+
434
+ - `neetru doctor` diagnóstico completo do ambiente: token CLI, Core acessível,
435
+ schema do `neetru.config.json`, valor de `NEETRU_ENV`, e versão do CLI
436
+ comparada com a `latest` no npm. Saída em tabela colorida (default) ou
437
+ JSON (`--json`). Diferença pra `validate`: doctor inclui environment +
438
+ version mismatch (warning, não fail).
439
+ - `neetru upgrade` verifica `dist-tags.latest` em
440
+ `https://registry.npmjs.org/@neetru/cli` e exibe instrução de upgrade
441
+ (`npm install -g @neetru/cli@latest`). Sem auto-install — não quebra
442
+ pipelines pinados.
443
+ - `neetru autocomplete <bash|zsh|pwsh>` — gera script de shell completion
444
+ pra os 22 subcomandos top-level. Usuário cola na config do shell:
445
+ `neetru autocomplete bash >> ~/.bashrc`.
446
+ - `neetru config set telemetry.enabled <true|false>` — opt-in explícito de
447
+ telemetria. Default desligado. Quando ligado, CLI envia eventos
448
+ anonimizados pra `POST /sdk/v1/telemetry/log` (placeholder na v2.0).
449
+ Nunca envia tokens, paths absolutos ou conteúdo de arquivos.
450
+
451
+ ### Bumped
452
+
453
+ - `1.4.0 → 2.0.0` (major bump por convenção de estabilidade — sem breaking
454
+ changes funcionais).
455
+
456
+ ### Não publicado no npm ainda
457
+
458
+ Bump local. Publish manual pra npm fica deferido — owner aprovará. Build
459
+ local (`npm run build` em `cli/`) gera o `dist/` pronto pra publicação.
460
+
461
+ ## [1.3.0]2026-05-06
462
+
463
+ ### Adicionado
464
+
465
+ - `neetru add <feature>` — copia template em `cli/templates/{feature}/*` para
466
+ `src/lib/neetru/{feature}/*` no projeto atual. Features: `auth`, `billing`,
467
+ `usage`, `users`, `support`. Suporta `--force` pra sobrescrever.
468
+ - `neetru mocks reset` — reseta `.neetru/dev-fixtures.json` para `{}` (útil
469
+ com `NEETRU_ENV=dev`).
470
+ - `neetru env switch <dev|workspace|production>` — atualiza/insere
471
+ `NEETRU_ENV=<value>` em `.env.local` preservando as outras chaves.
472
+ - `neetru logs` ganhou flags:
473
+ - `--product <productId>` filtra logs por produto.
474
+ - `--channel <channel>` filtra por channel (stdout/stderr/app/...).
475
+ - `--correlation-id <uuid>` — filtra por correlation ID.
476
+
477
+ ### Templates novos (`cli/templates/`)
478
+
479
+ - `auth/sign-in.tsx`, `auth/callback.ts`
480
+ - `billing/page.tsx`, `billing/checkout.ts`
481
+ - `usage/track.ts`
482
+ - `users/profile.tsx`
483
+ - `support/ticket-form.tsx`
484
+
485
+ ### Não publicado no npm ainda
486
+
487
+ Bump local `1.2.0 → 1.3.0`. Publish pra npm fica deferido — owner aprovará
488
+ manualmente quando quiser. Build local (`npm run build` em `cli/`) já compila.
489
+
490
+ ## [1.2.0] — 2026-05-06
491
+
492
+ **Consolidação das duas linhas paralelas.** Esta versão unifica os comandos das duas linhas de CLI que estavam coexistindo:
493
+
494
+ - **`@neetru/cli@1.0.x` (publicada no npm)**: linha *workspace-centric* com `init`, `add`, `validate`, `generate-types`, `whoami`, `login`, `status`, `logs`, `deploy`, `open`. APIs: `/api/v1/cli/workspace/*`.
495
+ - **`@neetru/cli@0.1.0` (monorepo, não publicada)**: linha *server-centric* com `ai`, `init`, `config`, `login`, `logout`, `whoami`, `build`, `deploy`, `publish`. APIs: `/api/v1/cli/{catalog,deploy,servers}`.
496
+
497
+ As duas falam **APIs distintas e complementares** do mesmo Neetru Core, refletindo a topologia real do produto:
498
+
499
+ ```
500
+ Workspace (prototipação) ──build/promote──► Server VM ou Cloud Run (produção)
501
+ ```
502
+
503
+ A `1.2.0` traz ambos os conjuntos de comandos numa única CLI. O monorepo passa a ser a fonte canônica.
504
+
505
+ ### Adicionado em relação a `1.0.1`
506
+
507
+ Comandos da linha *server-centric* (deploy via VM agent ou Cloud Run):
508
+
509
+ - `neetru ai` — REPL multi-model (Claude/OpenAI/Gemini) com contexto Neetru-aware
510
+ - `neetru build`empacota produto local em tarball + manifest com sha256, detecção automática de stack (node/docker/php-apache/static)
511
+ - `neetru deploy` — pipeline E2E interativo (escolha de produto/server/domain/port + polling status até estado terminal). Suporta `--non-interactive` para CI.
512
+ - `neetru publish` — registra produto no catálogo público (`public_products`), com `--draft` e `--unpublish`
513
+ - `neetru config {set|get|path}` — gerenciamento de chaves de API e config local
514
+ - `neetru logout` limpa credenciais
515
+ - `neetru login --token nrt_<keyId>_<secret>` — modo CI/legacy paralelo ao Device Code OAuth
516
+ - `neetru login --json`saída machine-readable para scripts
517
+
518
+ ### Mantido de `1.0.1` (re-implementado em TypeScript com convenções do monorepo)
519
+
520
+ - `neetru status --client-id <id>` — status de workspace (build/deploy último, domínio, tier, expira em N dias)
521
+ - `neetru logs --client-id <id>` visualiza logs do workspace; suporta `-f` follow + `-n N` lines + `--since 30m` + `--level error`
522
+ - `neetru validate` health-check da config local + ping `/api/health` + whoami
523
+ - `neetru open [target]` — abre dashboard, builds, logs, workspaces, products, servers, incidents no browser
524
+ - `neetru init <name>` — agora gera projeto Next.js 15 OU Node API (Fastify) com schema canônico v2
525
+
526
+ ### Backlog 1.3.x
527
+
528
+ Comandos que ainda dependem de design/templates novos:
529
+
530
+ - `neetru add <feature>` — scaffolds OAuth/billing/usage/users
531
+ - `neetru generate-types` — codegen TypeScript de planos/features/entitlements
532
+
533
+ ### Alterado
534
+
535
+ - Package agora é ESM nativo (`"type": "module"`). Imports usam `.js` extension.
536
+ - `neetru login` agora usa Device Code OAuth (RFC 8628) por default; `--token` permanece para CI.
537
+
538
+ ### Migração de `1.0.x`
539
+
540
+ Não há caminho 100% automático porque a config local muda:
541
+
542
+ - `1.0.x` lia `neetru.json` workspace-local com `{clientId, coreUrl}` + var de ambiente `NEETRU_CLIENT_SECRET`
543
+ - `1.2.0` lê `~/.config/neetru-cli/auth.json` (Bearer token salvo por `neetru login`) + `neetru.config.json` por projeto com `{slug, runtime, publish}`
544
+
545
+ Recomendação:
546
+
547
+ 1. `npm uninstall -g @neetru/cli && npm install -g @neetru/cli@1.2.0`
548
+ 2. `neetru login` (Device Code) — gera credencial Bearer no novo formato
549
+ 3. Para comandos workspace (`status`, `logs`, `open`), passe `--client-id <oauthClientId>` explicitamente — o `clientId` continua sendo o `oauthClientId` do seu workspace, achável em UI Core `/workspaces/{id}`
550
+
551
+ ## [1.0.1] — anterior
552
+
553
+ Linha workspace publicada no npm. Comandos: `init`, `add`, `validate`, `generate-types`, `whoami`, `login`, `status`, `logs`, `deploy`, `open`. APIs: `/api/v1/cli/workspace/*`.
554
+
555
+ ## [1.0.0] — anterior
556
+
557
+ Primeira versão pública.
558
+
559
+ ## [0.1.0] — interno (não publicado)
560
+
561
+ Snapshot interno do monorepo durante desenvolvimento da Sprint 1+. Substituído por `1.2.0`.