@neetru/cli
v2.35.0
Published
Neetru Developer Kit — scaffold, AI assistant, publish, build e deploy de produtos SaaS Neetru via Core (VM-based agents)
Readme
@neetru/cli
Developer Kit oficial da Neetru — scaffolding, IA Neetru-aware, deploy de produtos SaaS, gestão de workspaces, bancos isolados por produto, e mais 40+ comandos pra operar todo o ecossistema Neetru via terminal.
Instalação
npm install -g @neetru/cliBootstrap completo da máquina dev (Node, gcloud, Docker, Firebase CLI, deps NPM, GCP ADC):
neetru bootstrapLogin no Core via OAuth Device Code Flow:
neetru loginValidar estado:
neetru doctorQuickstart — criar produto SaaS novo
neetru new gestovendas --env=dev --tier=dev --customer=neetruCria produto + workspace + scaffold local Next.js 15 + instala deps + abre cockpit no browser.
Comandos principais
| Comando | O que faz |
|---|---|
| neetru bootstrap | Setup da máquina dev (binários + deps + ADC) |
| neetru login / logout / whoami | Auth OAuth Device Code Flow |
| neetru doctor | Diagnóstico saúde (5 checks rápidos) |
| neetru new <slug> | Criar produto completo (registry + workspace + scaffold) |
| neetru init <name> | Só scaffold local Next.js + Firebase |
| neetru add <feature> | Adicionar features ao scaffold (auth, billing, etc) |
| neetru deploy | Pipeline de deploy interativo (cloud-run / vm / workspace) — roda docs check e só avisa |
| neetru docs init [--com-api] [--migrar] | Mínimo do primeiro dia do docs/ do produto (idempotente); --migrar só acrescenta frontmatter + relatório |
| neetru docs new <tipo> "<título>" | Doc novo a partir do modelo, na pasta e com o nome do protocolo |
| neetru docs check [--changed] [--strict] | Valida os docs do produto offline (códigos FM/TI/NM/LK/PB/LC + PR001–PR004) |
| neetru docs sync [--dry-run] | Publica os docs do produto no Core (só os sem erro; nada é apagado) |
| neetru build [--app <pasta>] [--stack ...] [--target-env dev\|workspace\|prod] [--env-file ...] [--no-cache] [--no-install] | Empacotar produto em tarball pra deploy (monorepo: --app apps/web, ou --cwd) |
| neetru smoke [--base-url ...] [--prod ...] [--health-path ...] [--routes csv] [--json] | Percorrer as páginas do produto local antes do deploy (alcance + login + DB) + smoke de prod opcional |
| neetru promote | Promover dev → staging → prod |
| neetru env switch <target> | Trocar NEETRU_ENV no .env.local |
| neetru env set --service=X --set KEY=VAL | Setar env vars de serviço Cloud Run |
| neetru secrets set CHAVE --env <ambiente> [--generate \| --stdin \| --from-file <caminho>] | Segredo do próprio produto (app em VM): o valor vai direto pro Secret Manager e nunca entra pela linha de comando; --generate = o Core sorteia |
| neetru secrets list / archive CHAVE --env <ambiente> | Listar só os nomes / arquivar um segredo do produto |
| neetru ar create <name> | Criar repositório Artifact Registry |
| neetru hosting create-mapping --service=X --domain=Y | Domain mapping |
| neetru admin database create --product-id=X --engine=cloud-sql-postgres | Registrar banco isolado por produto (staff control plane) |
| neetru admin database engines | Listar engines suportados (firestore-instance, cloud-sql-postgres, cloud-sql-mysql, vm-postgres-single, vm-mysql-single, nosql-vm, …) |
| neetru db init / apply / migrations | Banco por produto no fluxo dev (registra + schema + migrations) |
| neetru dev | Banco Docker local + watch de schema (salvar = aplicado) |
| neetru dev up | Banco do produto em container (Docker Compose) + URL de conexão pro .env.local |
| neetru dev exec <script> | Roda <script> com os emuladores Firebase do Core (exige o repo do Core; CI do Core) |
| neetru cloud-run pause/resume/delete <service> | Controle Cloud Run |
| neetru products list/create/update | Registry de produtos |
| neetru workspaces create/list/get/advance | Instâncias por cliente |
| neetru deployments create/rollback | Histórico de deploys |
| neetru tenants list/create/update/suspend | Gerenciar tenants |
| neetru audit tail | Tail de audit_logs/ em tempo real |
| neetru billing summary | Resumo de billing |
| neetru servers list/provision/deactivate | Gerenciar servidores |
| neetru agent release/yank/canary | Gerenciar releases do agente |
| neetru support tickets list/reply/assign | Suporte inbox staff |
| neetru dns zones list / hosting list | Listar DNS + customer domains |
| neetru builds list | Listar Cloud Build |
| neetru dr exports/restore | Disaster Recovery |
| neetru logs | Ver logs de produtos |
| neetru status | Visão geral do ecossistema |
| neetru open <produto> | Abrir cockpit do produto no browser |
| neetru ai | REPL IA Neetru-aware (Groq, NVIDIA NIM, OpenAI ou o AI Gateway da Neetru via neetru login) |
| neetru ui | Menu interativo do CLI |
| neetru publish | Publicar produto no catálogo público |
| neetru upgrade | Auto-update do CLI |
| neetru autocomplete <bash\|zsh\|pwsh> | Gerar script autocomplete |
Atalhos: neetru ar = artifact-registry, neetru menu = ui.
40+ subcomandos. Quase todos suportam --json pra automação.
Docs do produto (neetru docs init|new|check|sync) — 2.31.0
Padrão: PROTOCOLO_DOCS_PRODUTOS_SAAS.md do Core (versão 1). O docs/ de cada produto segue a mesma taxonomia da wiki do Core (categoria + subcategoria por assunto, type à parte) e nomes MAIÚSCULO_COM_UNDERLINE.
neetru docs init # README, CHANGELOG, docs/index.md, visão, arquitetura, runbook de deploy
neetru docs init --com-api # + docs/api/API_V1.md (o produto expõe /api/v1)
neetru docs init --migrar # repo que já tem docs: frontmatter inferido + relatório em docs/_audit/
neetru docs new adr "Usar Postgres para vendas"
neetru docs new relatorio "Auditoria de UX da tela de caixa"
neetru docs check --changed # catraca: só o que mudou contra a branch principal
neetru docs sync --dry-run # o que subiria para o Coreneetru initeneetru newjá rodamdocs init(--sem-docspula).neetru deployrodadocs checke só avisa — nunca bloqueia. Com"docs": { "publishOnDeploy": true }noneetru.config.json, o deploy de produção publica os docs no fim; falha na publicação não derruba o deploy.--sem-docspula as duas coisas.- A taxonomia vem embutida na CLI (funciona offline); quando o Core expõe
GET /api/cli/v1/docs/taxonomy, ocheckusa a do Core e avisa se a embutida estiver velha.
Dev local (neetru dev, neetru dev up)
O que roda na máquina do dev de produto hoje:
| Peça | Como |
|---|---|
| SDK sem conta Neetru | NEETRU_ENV=dev → mocks em memória (login fixture, uso zerado, banco em memória). neetru mocks reset limpa as fixtures. |
| Banco real do produto | neetru dev (container + reaplica db/schema.ts a cada save) ou neetru dev up (só sobe o container e imprime a URL de conexão). Engine vem do projeto. |
| App | npm run dev, fora de container. |
| Agente / Core locais | Ainda não existem para produto. Deploy e migração pelo agente só acontecem na VM. |
# Na raiz do produto (com database.engine no neetru.config.json):
neetru dev up
# → gera neetru-compose.dev.yml e sobe o banco (docker compose up -d --wait)
# → imprime a conexão, ex. postgresql://postgres:neetru_dev@localhost:5432/app
docker compose -f neetru-compose.dev.yml down # para
# CI do Core (na raiz do Core, onde tem firebase.json): roda o script com os
# emuladores Firebase e propaga o exit code.
neetru dev exec "npm run test:integration"Contexto do projeto local:
# Projeto ligado a um produto já existente no Core:
neetru dev use --product meu-produto --sync
# Protótipo local ainda não cadastrado no Core:
neetru dev use --prototype meu-rascunho
# Ver o contexto dev-local efetivo:
neetru dev status
# Sincronizar bancos dev-local do Core para .neetru/db.json:
neetru dev sync --write-db
neetru dev(sem subcomando) mantém o modo legado: banco Docker local + watch de schema. Flags:dev up --core-port <n>(porta do app nas instruções, default 3000);dev exec --only firestore,auth,functions --core-path <dir>. O arquivo.neetru/dev.jsonguarda o contexto local: produto Core ou protótipo, Core path e emuladores padrão.
Build — env do bundle (NEXT_PUBLIC_NEETRU_ENV)
neetru build sempre serve pra gerar artefato de deploy — nunca pra dev local (isso é next dev/neetru dev up). Por isso, pra stacks node/static (produtos Next.js), o build sempre força NEXT_PUBLIC_NEETRU_ENV=<targetEnv> via spawn-env no processo do npm run build — default prod, sem nenhuma ação do dev:
neetru build --product=meu-produto # NEXT_PUBLIC_NEETRU_ENV=prod (default)
neetru build --product=meu-produto --target-env=workspaceIsso existe porque o Next.js carrega .env.local (arquivo do disco do dev, nunca deletado) antes de .env.production — e valores já definidos não são sobrescritos por arquivos carregados depois. Sem essa proteção, um .env.local esquecido com NEETRU_ENV=dev fazia o bundle de PRODUÇÃO compilar com o SDK Neetru em modo mock (MockAuth), desativando o login real silenciosamente (incidente pdv-agiliza, 2026-07-22).
Se o produto envolver next.config.mjs com withNeetruBuildGuard (@neetru/sdk/build-guard, @neetru/sdk >= 3.1.15), neetru build confere pós-build que o env realmente compilado bate com o esperado — e recusa empacotar o tarball se divergir, em vez de deployar um bundle quebrado silenciosamente.
Build de monorepo (pnpm, yarn, bun ou npm workspaces)
Deploy de monorepo na VM ainda não funciona. O agente da VM (1.6.80) não reconhece o app que fica dentro de uma pasta do pacote (
apps/web/server.js): em vez de pular a instalação, ele rodanpm rebuildna raiz do pacote e, se falhar,npm install— o mesmo caminho que já derrubou deploy em VM pequena (exit 137). Para a VM, mantenha o seu empacotador próprio até sair a versão do agente que reconhece o app aninhado (bug_bc72fe7e no agente; origem bug_678ddc98). Oneetru build --appabaixo já monta o pacote; o que falta é o agente saber instalá-lo.
Rode da raiz do monorepo e aponte o app com --app (--cwd é o mesmo):
neetru build --app apps/web --product meu-produto
neetru deploy --product meu-produto # da mesma pasta: usa o pacote que o build gerou (na VM, veja o aviso acima)- Onde sai o pacote: em
.neetru-build/da pasta onde você rodou o comando — é lá que oneetru deployprocura. Oneetru.config.jsonpode ficar no app ou na raiz (o do app vale mais). A versão vem dopackage.jsondo app. - Gerenciador de pacotes, nesta ordem: (1) o campo
packageManagerdopackage.jsondo app; (2) o lockfile da pasta do app (pnpm-lock.yaml,yarn.lock,bun.lock/bun.lockb,package-lock.json), que vem antes de tudo o que está na raiz, inclusive dopackageManagerda raiz; (3) sem lockfile no app, a CLI sobe até a raiz do workspace, e lá opackageManagerdopackage.jsonda raiz vale mais que o lockfile da raiz. A raiz só conta se se declara workspace (pnpm-workspace.yamlouworkspacesnopackage.json), e a busca para na pasta que tem.git. Achada a raiz, a instalação roda nela e o scriptbuildroda na pasta do app. Sem lockfile nenhum, fica o npm, como sempre. - Cuidado com lockfile solto no app: um
package-lock.jsonesquecido emapps/webde um monorepo pnpm faz a CLI escolher o npm e instalar só dentro deapps/web, onde as dependênciasworkspace:*falham. Apague o lockfile solto antes do build. - Next.js com
output: 'standalone': no monorepo o Next.js põe o app dentro do standalone, no mesmo caminho que ele tem no repositório (.next/standalone/apps/web/server.js). A CLI lê esse caminho de.next/required-server-files.json(camporelativeAppDir, gravado pelo próprio Next.js no build). Se o arquivo não traz o campo (Next.js antigo), ela procura oserver.jspela árvore. O pacote leva o standalone inteiro,.next/staticepublicvão para dentro deapps/web/, e oneetru deploymanda o entrypointapps/web/server.jspara o Core. - Quando a CLI recusa: se o Next.js registrou o app num lugar e o
server.jsnão está lá, ou registrou um lugar fora do standalone (ooutputFileTracingRootprecisa ser uma pasta acima do app), o build para com exit 1 em vez de empacotar um pacote que não sobe. - Cloud Run sem Dockerfile: o Dockerfile que o
neetru deploy --target cloud-rungera quando o projeto não tem um reconhece o monorepo (bug_1dcf8e03): detecta o gerenciador do app (mesma regra doneetru build --appacima), builda com o contexto na raiz do workspace (onde mora o lockfile —workspace:*só resolve assim) e aponta oCMD/COPYdo standalone para o caminho aninhado do app (apps/web/server.js). Rodeneetru deployde dentro do app (cd apps/web && neetru deploy …), como noneetru build --app. Testado com pnpm (fixture de monorepo) e npm de app único (caso de sempre); yarn berry com PnP e workspace nativo npm/yarn sem teste próprio — fora desses dois casos, escreva o seu Dockerfile.
Segredo no pacote público bloqueia o deploy (2.30.0)
A credencial nrt_ do produto é só de servidor. Antes de enviar o pacote, neetru deploy varre o que é servido ao navegador — .next/static/**, public/**, out/**, dist/**, build/** (na stack static, o pacote inteiro; node_modules nunca) — procurando:
nrt_…enpk_…(credenciais Neetru);-----BEGIN … PRIVATE KEY-----com o material da chave (só o cabeçalho não conta);- o valor de envs públicas (
NEXT_PUBLIC_*,EXPO_PUBLIC_*,VITE_*,REACT_APP_*,PUBLIC_*) cujo nome contémKEY/SECRET/TOKEN(lidas de.env,.env.production,.env.local,.env.production.local,--env-filee do ambiente). Valores públicos por desenho do provedor (Stripepk_live_/pk_test_, chave web Google/FirebaseAIza…, reCAPTCHA6L…) são ignorados.
Achou → o deploy falha (exit 1, public_secret_in_bundle) mostrando arquivo e tipo — nunca o segredo (no máximo 8 caracteres iniciais, mascarados). Pacote ilegível também falha (public_secret_scan_failed).
Correção: tire a chave do código do navegador/app; o navegador/app chama a API do seu produto com o token do usuário e o backend usa @neetru/sdk com NEETRU_API_KEY (ver verifyAccessToken no SDK ≥ 3.8.0).
Emergência (fica registrado no deploy — só caminho e tipo, nunca o valor):
neetru deploy --allow-public-secret "chave antiga já revogada, ticket #123"Limites: --artifact-url (pacote remoto) e --image (imagem pronta, cloud-run) não passam pelo CLI e não são varridos — o deploy avisa. Em target=cloud-run sem --image, a varredura é nas pastas públicas do disco antes do build da imagem.
Deploy na VM: um app por produto e ambiente
Na VM (--target vm) quem escolhe a porta do app é o Core; --port é ignorado (a CLI avisa). O Core reconhece o app pelo produto + ambiente: um novo neetru deploy --product X --env prod substitui o app de X em prod que está no ar — o endereço de prod passa a servir o deploy novo, e não sobe um segundo app ao lado.
Para ter dois apps (ex.: site e API em endereços diferentes), cadastre o segundo como produto próprio e faça o deploy de cada um com o seu --product:
neetru products create --name "Meu SaaS API" --slug meu-saas-api # exige papel admin ou operator
neetru deploy --product meu-saas-api --env prod --target vm --server <id>O deploy do produto novo exige que a chave da CLI o alcance: a de admin alcança todos os produtos; uma chave com escopo de produto só alcança os dela, e o deploy do novo volta 403 forbidden_product — nesse caso o deploy fica com um admin.
Enquanto o conserto do Core para o bug_fe30f035 não estiver no ar, o 1º deploy do produto novo na VM é recusado pelo Core: o produto nasce com staging e prod no destino workspace, e o deploy na VM volta 400 vm_deploy_failed ("Ambiente prod tem destino 'workspace', não 'vm'. Migre o destino antes (changeEnvironmentTarget)…"). A CLI não tem comando para trocar o destino de um ambiente. Quando essa recusa acontece, a CLI a explica, e o caso fica com um admin do Core.
Cada produto tem endereço, banco e segredos próprios. Se os dois precisam do mesmo banco, separar não serve (o banco é isolado por produto): sirva a API pelo próprio app (ex.: rotas /api), no mesmo endereço. O mesmo texto aparece em neetru deploy --help.
Smoke local antes do deploy (neetru smoke)
Roda contra o servidor dev local (next dev / neetru dev up) e percorre as páginas do produto antes de neetru build + neetru deploy — pega página quebrada, login que não renderiza ou banco fora do ar sem subir nada em produção.
# suba o dev local primeiro (ex: next dev na porta 3000), depois:
neetru smoke
neetru smoke --base-url=http://localhost:9002 --health-path=/api/health
neetru smoke --routes=/,/login,/dashboard # rotas explícitas (pula a auto-descoberta)
neetru smoke --prod=https://meu-saas.neetru.com # + smoke básico de prod (GET / e health, espera 200)
neetru smoke --json | jq '.summary' # saída de 1 linha machine-readableO que verifica (cada check vira ✓ pass / ✗ fail / ⚠ warn):
- Alcance das rotas — auto-descobre as rotas do App Router (
app/**/page.*) e do Pages Router legado (pages/**/*, exceto_app/_document/api). Route groups(...)são removidos; segmentos dinâmicos[param]/[...slug]são pulados com aviso (não há valor de amostra trivial). GET em cada rota: passa em 200–399 sem marcador de erro no corpo; falha em>=400ou marcador (Application error,Internal Server Error,__next_error__, 404 do Next, título 500). - Login carrega — acha a rota de login e confere que renderiza; sem um botão/afford de login detectado vira aviso, não falha; não-200 falha.
- Banco / health — GET no
--health-path: 200 com corpo saudável passa; 404 vira aviso (produto não expõe health path — DB não verificável por aqui); qualquer outro não-200 falha. - Smoke de prod (só com
--prod) — GET em<prod>/e<prod><health-path>, espera 200 em cada.
Exit 1 se qualquer check falhar (avisos não bloqueiam). Abordagem leve, sem Playwright/headless browser — o CLI é publicado no npm e não pode ganhar uma dependência de ~300MB de browser. Captura de erro de console (que exigiria um browser real) fica para um v2 documentado, atrás de um flag opt-in que instale o headless sob demanda.
Configuração
Token Bearer fica em ~/.config/neetru-cli/auth.json (chmod 0600 em Unix, NTFS ACL em Windows) — gerado por neetru login via OAuth Device Code Flow. Configs gerais ficam em ~/.config/neetru-cli/config.json (Linux/macOS) ou %APPDATA%\neetru-cli\config.json (Windows):
| Chave | Valor |
|---|---|
| neetruApiUrl | URL base do Core (default https://api.neetru.com). Allowlist desde 2.11.0: *.neetru.com + localhost; demais hosts exigem --allow-untrusted-url |
| defaultModel | groq / nvidia / openai / gateway / auto (default auto): o modelo do neetru ai aberto sem -m. No auto, a CLI escolhe entre os provedores com chave, gratuitos primeiro (Groq, NVIDIA NIM; a OpenAI só sem eles) |
| telemetry.enabled | Telemetry opt-in (default false) — desde 2.11.0 emite eventos anônimos pra /api/sdk/v1/telemetry/log |
| neetruApiKey | (legado) Token em Conf — substituído por auth.json. Será removido em 2.12.0 |
neetru config set telemetry.enabled true
neetru config get neetruApiUrl
neetru config path # mostra caminho do config file
neetru config set neetruApiUrl https://staging.neetru.com # subdomínio neetru.com — OK
neetru config set neetruApiUrl http://my-proxy.local --allow-untrusted-url # explicit opt-inOutput JSON
neetru products list --json | jq '.[] | select(.status == "ativo")'
neetru audit tail --json | jq 'select(.action | startswith("billing"))'Auth & Segurança
- OAuth Device Code Flow (RFC 8628) pra login interativo — não armazena password
- Tokens salvos em
~/.config/neetru-cli/auth.json(chmod 0600 em Unix, NTFS ACL em Windows). Desde 2.11.0 o resolver canônico (getActiveTokenSync) prefere esse arquivo sobre o Conf storage legado (que será removido em 2.12.0) - URL allowlist (desde 2.11.0):
neetruApiUrlrejeita hosts fora de*.neetru.com+localhostsem--allow-untrusted-url— fecha vetor de exfiltração do Bearer token - Rate-limit por método HTTP: GET 120/min, POST/PUT/PATCH 30/min, DELETE 5/min
- Step-up MFA (TOTP) obrigatório em operações destrutivas: sessão de 1h (
neetru auth mfa-session),--mfa-token <code>ou prompt (em--json/sem TTY: fail-closed). Desde 2.28.10 também emagent release(todos os canais),ops reg-token,ops bootstrap-admin(quando já há admin;--reactivatereativa staff desligado),ops migrate cli-keys(fora do dry-run),vm provisionedeploy --env prod agent releasesó aceita binários emhttps://core.neetru.com/releases/...ou no bucket GCS de releases (validado localmente, mesma regra do Core)- Dry-run disponível em comandos de mutação:
--dry-runmostra efeito SEM aplicar - Telemetry opt-in (desde 2.11.0): habilitando
telemetry.enabled=trueo CLI emite{command, durationMs, ok, exitCode}anônimo viainstallIdUUID. Zero token/path/email/env vazam
Stack
- TypeScript 5 ESM-first
- Node 20+ (
engines.node: >=20; Node 22 LTS recomendado) - Sem
node-fetch/axios: fetch global nativo - Commander 12 (CLI framework) + Inquirer 10 (prompts) + Chalk 5 + Ora (spinners)
Mais info
- Repo: github.com/Neetru/neetru-core
- Docs: docs.neetru.com
- SDK complementar:
npm install @neetru/sdk - Issues / suporte: abrir issue no repo ou
neetru support
Licença
MIT © Neetru
