⚡ pnpm dev vs pnpm dev:app
Dois comandos, dois propósitos. Confundi-los faz você passar minutos achando que algo "não funciona" quando na verdade você não subiu o core Rust.
pnpm dev
Só o Vite dev server.
- • Hot reload de UI puro
- • Sem core Rust → RPC falha
- • Útil para storybook-like de componentes
- • Boot em ~1 segundo
pnpm dev:app
Ciclo Tauri completo.
- • Runtime CEF + core in-process
- • Carrega
scripts/load-dotenv.sh - • Chama
pnpm tauri:ensureprimeiro - • Boot 10-30s na primeira vez
⌨️ Comandos
# UI pura (sem core)
pnpm dev
# Desktop completo (RECOMENDADO)
pnpm dev:app
# Build de produção da UI
pnpm build
💡 Regra prática
99% do tempo você quer pnpm dev:app. Só use pnpm dev quando estiver iterando em CSS/UI pura e não precisa de invocar RPC do core.
Hot reload
Funciona em ambos. dev:app também recompila Rust quando muda app/src-tauri/.
Logs do core
Aparecem no terminal que rodou dev:app. Frontend logs no devtools.
Cmd+Q
Mata core junto com a GUI. CoreProcessHandle gerencia o lifecycle.
Devtools
Cmd+Opt+I (macOS) abre devtools do CEF para inspecionar a UI.
🔄 Fluxo de boot da Tauri shell
Desde PR #1061 não existe mais sidecar binário. O core roda como tokio task dentro do mesmo processo do Tauri host. Entender o boot ajuda a debugar.
Tauri host inicia
app/src-tauri/src/lib.rs
Registra IPC handlers, prepara janela, configura logging file-based.
CoreProcessHandle spawna o core
app/src-tauri/src/core_process.rs
Inicia o JSON-RPC server como tokio task. Gera OPENHUMAN_CORE_TOKEN hex aleatório. Bind em 127.0.0.1:<port>/rpc.
Frontend carrega no CEF
Vite dev server ou bundle estático
React monta a provider chain: Sentry → Redux → PersistGate → CoreStateProvider → ChatRuntimeProvider → HashRouter.
Handshake RPC via core_rpc_relay
Tauri IPC bridge
Frontend chama invoke('core_rpc_relay', ...) que faz HTTP autenticado para o core. Nunca fetch() direto — evita preflight CORS.
CoreStateProvider snapshot
Auth e core state
Chama fetchCoreAppSnapshot() — auth tokens vivem no core, não no redux-persist.
⚠️ Sidecar não existe mais
pnpm core:stage é no-op hoje — só ecoa mensagem. scripts/stage-core-sidecar.mjs foi removido. Não fique procurando processo separado de core.
🧰 Core standalone para debug
# Rodar core sozinho (sem Tauri)
./target/debug/openhuman-core serve
# Token gerado em:
# {workspace}/core.token
# Default workspace: ~/.openhuman
# Staging: ~/.openhuman-staging
🐛 Debug runners bounded
Rodar Vitest/WDIO/cargo direto despeja centenas de linhas no terminal. Os wrappers em scripts/debug/ limitam o stdout a um tamanho amigável e teiam o log completo em target/debug-logs/.
⌨️ Vitest (unit)
# Suite completa
pnpm debug unit
# Um arquivo
pnpm debug unit src/components/Foo.test.tsx
# Filtro por nome de teste
pnpm debug unit -t "renders empty state"
# Combinado + raw output
pnpm debug unit Foo -t "renders empty" --verbose
⌨️ WDIO E2E (um spec por vez)
pnpm debug e2e test/e2e/specs/smoke.spec.ts
pnpm debug e2e test/e2e/specs/cron-jobs-flow.spec.ts cron-jobs --verbose
⌨️ cargo (Rust)
# Delegates a scripts/test-rust-with-mock.sh
pnpm debug rust
pnpm debug rust json_rpc_e2e
⌨️ Inspecionar logs salvos
pnpm debug logs # lista 50 mais recentes
pnpm debug logs last # imprime o mais recente (~400 linhas)
pnpm debug logs unit # mais recente com prefixo "unit"
pnpm debug logs last --tail 100
💡 Por que isso existe
Foi pensado para agentes (LLMs) lendo terminal output — context window é limitado. Mas humanos também ganham: você vê o resumo, e se quiser o detalhe, abre o log.
🎭 Mock API: backend de mentirinha
Para rodar testes sem rede real e sem flakes de timing, o repo tem um mock backend em scripts/mock-api-server.mjs. É compartilhado por Vitest unit, E2E e Rust tests.
📁 Arquivos relevantes
scripts/mock-api-core.mjs— core do mock (rotas e estado)scripts/mock-api-server.mjs— server HTTP que embrulha o coreapp/test/e2e/mock-server.ts— wrapper para WDIO E2Escripts/test-rust-with-mock.sh— sobe mock antes de cargo test
🔧 Endpoints admin
GET /__admin/health— alive checkPOST /__admin/reset— limpa estado entre testesPOST /__admin/behavior— injeta comportamento (latência, erro, payload custom)GET /__admin/requests— lista requests recebidas (asserção)
⌨️ Rodar manualmente
# Sobe o mock e deixa rodando
pnpm mock:api
# Testes Rust com mock automático
pnpm test:rust
# Spec Rust específico
bash scripts/test-rust-with-mock.sh --test json_rpc_e2e
✓ Vantagens
- ✓Determinístico — sem flake de rede
- ✓Reset entre specs garante isolamento
- ✓Behavior injection cobre edge cases
- ✓Sem credenciais necessárias
✗ Limitações
- ✗Não cobre mudanças do backend real
- ✗Precisa atualizar mock quando contratos mudam
- ✗Lógica de negócio fica fora — só shape de payload
🧹 Quality checks pré-commit
Os mesmos comandos que rodam no CI estão disponíveis localmente. Rodar antes de empurrar evita PR vermelho e economiza ciclos de review.
⌨️ Suite completa
# TypeScript (alias de compile)
pnpm typecheck
# ESLint
pnpm lint
# Format (Prettier + cargo fmt)
pnpm format # escreve
pnpm format:check # só verifica
# Testes
pnpm test # Vitest
pnpm test:coverage # com cobertura
pnpm test:rust # cargo via test-rust-with-mock.sh
pnpm rust:check # cargo check do shell
📐 Husky pre-push
O hook automático roda pnpm rust:check antes de qualquer push. Falha:
- • Você quebrou o Tauri shell → conserte e empurre novo commit
- • Algo pré-existente quebrado e não tocado por você →
--no-verifye nota no PR body
⚠️ Coverage gate
CI exige ≥80% nas linhas alteradas via .github/workflows/coverage.yml. diff-cover mistura lcov do Vitest e do cargo-llvm-cov. Abaixo do limite, o PR não mergeia. Adicione testes para o que você mudou, não só happy path.
format antes de commit
Rode pnpm format sem :check para escrever as correções. Sem stress no review.
test:coverage local
Antes de empurrar, rode local e veja se passa o gate antes do CI te avisar.
--no-verify regra
Só para breakage pré-existente. Documente no PR. Nunca para escapar de erros seus.
ESLint cache
Cache em .eslintcache torna runs subsequentes quase instantâneos.
🔧 Troubleshooting do primeiro boot
90% dos problemas de onboarding caem em três categorias. Saber identificar economiza horas.
Janela abre em branco e crasha
Sintoma: panic em cef::library_loader::LibraryLoader::new
Causa: CLI errada do Tauri foi sobrescrita.
# Fix
cargo install --locked \
--path app/src-tauri/vendor/tauri-cef/crates/tauri-cli
Porta 7788 ocupada
Sintoma: core falha ao bindar; erro EADDRINUSE
Causa: outro processo (talvez um core órfão) já escuta.
# Achar o processo
lsof -i :7788
# Mata
kill -9 <pid>
# Ou: trocar porta
export OPENHUMAN_CORE_PORT=7799
RPC retorna 401 / "Unauthorized"
Sintoma: UI carrega mas todas as chamadas falham
Causa: token bearer divergente entre core e frontend.
# Inspecionar token ativo
bash scripts/print-core-token.sh
# Se você setou OPENHUMAN_CORE_TOKEN manual,
# remova do .env — Tauri gera o seu.
🔍 Outros sintomas e onde olhar
- "Sidecar binary not found": docs antiga — sidecar foi removido em #1061; ignore
- Vite recompila infinitamente: verifique se algum arquivo do Tauri está sendo gravado por linter em loop
- Cargo build não termina: primeira vez é 5-15 min — aguarde
- Erro de TypeScript em produção mas não local:
pnpm typecheckusatsc --noEmit— confira
💡 Dica final
Quando travar, vá para gitbooks/developing/architecture.md e gitbooks/developing/cef.md. São as fontes narrativas mais completas. CLAUDE.md resume; gitbooks aprofundam.
📚 Resumo do módulo
fetch() direto — evita CORSpnpm debug unit/e2e/rust/logsPróxima trilha:
Trilha 3 - Arquitetura: como o core Rust, o shell Tauri e o frontend React conversam de verdade