@nomad-e/gaudi-cli
v3.0.0
Published
CLI para consumir a API Gaudencio-Cloud (workloads, volumes, tenants, containers)
Readme
gaudi-cli
CLI em Node.js para consumir a API Gaudencio-Cloud (workloads, volumes, tenants).
Instalação
cd cli
npm install
npm link # opcional: cria o comando global `gaudi-cli`Sem npm link, executa com node bin/gaudi-cli.js.
Configuração
A config é persistida em ~/.gaudi-cli/config.json (permissões 0600).
- Base URL da API: por omissão
https://gaudi-v2-api.factorai.cloud/api/v1(instância de produção). Define com a envGAUDI_API_URLou edita o ficheiro de config. - ERP Middleware: por omissão
https://erp-middleware.factorai.cloud. Define com a envERP_MIDDLEWARE_URL. - Token / tenant: guardados automaticamente após
auth login(o login sincroniza o tenant internamente).
Fluxo rápido
# 1. Autenticar (interativo: pede factorai_domain, username e password)
# Resolve erp_url/erp_db via ERP Middleware e sincroniza o tenant automaticamente.
gaudi-cli auth login
# 2. Listar o catálogo de imagens AI-native
gaudi-cli workload-type list
# 3. Criar e fazer deploy de um workload
gaudi-cli workload create -n "Documentos" -w 1
gaudi-cli workload deploy -i <id>
gaudi-cli workload status -i <id>
gaudi-cli workload logs -i <id>Comandos
auth
| Comando | Descrição |
|---------|-----------|
| auth login [--factorai-domain <d>] [-u <user>] [-p <pass>] | Autentica de forma interativa (3 dados) e sincroniza o tenant automaticamente |
| auth me | Mostra o utilizador autenticado |
| auth renew | Renova o access token usando o refresh token guardado (POST /auth/refresh) |
| auth logout | Revoga a sessão e limpa a config local |
| auth status | Mostra o estado da sessão local (sem chamar a API) |
O
auth loginpede apenas factorai_domain, username e password. Os detalhes ERP (erp_url,erp_dbname) são resolvidos automaticamente a partir dofactorai_domainvia ERP Middleware (companies/me?domain=<d>), e o tenant é sincronizado internamente — o utilizador final não precisa de invocar osync.
workload-type (catálogo de imagens AI-native)
| Comando | Descrição |
|---------|-----------|
| workload-type list [--show-inactive] | Lista o catálogo |
| workload-type create -k <key> -n <name> --image <img> [...] | Regista um tipo |
| workload-type get -i <id> | Mostra um tipo |
| workload-type update -i <id> [...] | Atualiza um tipo |
| workload-type delete -i <id> | Remove um tipo |
workload (instâncias por tenant)
| Comando | Descrição |
|---------|-----------|
| workload list [-t <tenant>] | Lista os workloads de um tenant |
| workload create -n <name> -w <type_id> [-t <tenant>] | Cria um workload (sem deploy) |
| workload get -i <id> [-t <tenant>] | Mostra um workload |
| workload update -i <id> [-t <tenant>] [...] | Atualiza um workload |
| workload delete -i <id> [-t <tenant>] | Remove um workload |
| workload deploy -i <id> [-t <tenant>] [--cpu <c>] [--mem <m>] [--volume-id <v> --volume-mount-path <p>] | Deploy on-demand do container |
| workload publish -i <id> [-t <tenant>] | Publica explicitamente o mapeamento de roteamento dinâmico (app-{slug}.{domain}) |
| workload stop -i <id> [-t <tenant>] | Para o container |
| workload status -i <id> [-t <tenant>] | Consulta o status |
| workload ports -i <id> [-t <tenant>] | Lista as portas expostas |
| workload logs -i <id> [-t <tenant>] [--tail <n>] | Mostra os logs |
| workload logs-stream -i <id> [-t <tenant>] [--tail <n>] [--raw] | Stream contínuo (SSE) dos logs em tempo real |
| workload attach -l <label> -c <container_id> [-t <tenant>] | Anexa um container Docker nativo |
| workload copy-file -i <id> --path <dir> --file <local> [--filename <name>] [-t <tenant>] | Copia um ficheiro local para dentro do container |
| workload copy-dir -i <id> --path <dir> --dir <local> [-t <tenant>] | Copia um diretório local (recursivo) para dentro do container |
| workload exec -i <id> -c <cmd> [-t <tenant>] [--workdir <dir>] [--user <u>] [--timeout <s>] | Executa um comando dentro do container |
volume (armazenamento Docker por tenant)
| Comando | Descrição |
|---------|-----------|
| volume list [-t <tenant>] | Lista os volumes |
| volume create -n <name> [-t <tenant>] | Cria um volume persistente |
| volume get -i <id> [-t <tenant>] | Mostra um volume |
| volume update -i <id> [-t <tenant>] [...] | Atualiza um volume |
| volume delete -i <id> [-t <tenant>] | Remove um volume |
daemon (renovação automática de token)
| Comando | Descrição |
|---------|-----------|
| daemon start | Inicia o daemon em background (processo orphan) que renova o token automaticamente antes de expirar |
| daemon stop | Para o daemon de renovação de token |
| daemon status | Mostra o estado do daemon (a correr / PID) |
O daemon é um processo orphan (detached) que sobrevive ao fim de cada invocação do CLI. Mantém a sessão viva renovando o access token a 50% do seu tempo de vida, usando o refresh token guardado. Inicia automaticamente após o
auth login— não é preciso correrdaemon startmanualmente. Oauth logoutpara o daemon automaticamente. O PID é guardado em~/.gaudi-cli/daemon.pidpara evitar duplicados.
Renovação de token (engenharia)
O gaudi-cli mantém a sessão viva renovando o access token antes de expirar, de duas formas complementares:
- Manual —
auth renewfazPOST /auth/refreshcom o refresh token guardado e persiste os novos tokens/sessão. - Automática — o daemon (processo orphan/detached) renova o token a 50% do tempo de vida do access token atual, sem precisar de o CLI estar a ser usado.
Como funciona:
- No
auth login(e noauth renew), o CLI gravatokenIssuedAtetokenExpiresAt(epoch ms) na config, calculados a partir doexpires_indevolvido pela API. - O daemon lê esses timestamps e calcula o ponto de renovação:
issuedAt + (expiresAt - issuedAt) × 0.5. Quando esse momento chega, fazPOST /auth/refreshe atualiza a config com os novos tokens e timestamps. - Se os timestamps não existirem (config antiga), o daemon renova a cada 60s como fallback.
- O daemon é gerido por um ficheiro PID (
~/.gaudi-cli/daemon.pid) para evitar duplicados —daemon startnão lança um segundo processo se já houver um a correr. - Inicia automaticamente após o
auth login— não é preciso correrdaemon startmanualmente. Odaemon start/stop/statusexistem para gestão manual (ex: parar o daemon). - O
auth logoutpara o daemon automaticamente.
Multiplataforma: o spawn usa
detached: true+windowsHide: true(no Windows,detachedabriria uma janela de console nova — é escondida). O daemon limpa o PID file de forma graciosa ao receberSIGTERM/SIGINTno Unix; no Windows odaemon stopremove o PID file antes de terminar o processo.
Opções globais
--json— saída em JSON puro (máquina/IA)-h, --help— ajuda de qualquer comando-t, --tenant <id>— ID do tenant (default: o guardado peloauth login)
Testes
A suíte usa o runner nativo do Node (node:test) — sem dependências extra.
cd cli
npm testCobre:
- Unit (
test/api.test.js,test/config.test.js,test/output.test.js) — cliente HTTP (comfetchmockado), persistência de config e formatação de output. - Integração (
test/cli.integration.test.js) — sobe um servidor HTTP local que imita a API e executa o CLI como subprocesso, verificando parsing de comandos, consumo da API e output.
Notas
- Tenant: o
tenant_idé resolvido por omissão a partir da config (apósauth login). Pode ser sobrescrito com-t <id>em qualquer comando de tenant-scoped. Os comandosworkloadevolumesão scoped por tenant. - Gestão de tenants: não há comandos
tenantexpostos no CLI — o tenant é sincronizado automaticamente peloauth login(via ERP Middleware). O módulosrc/tenant.jsexiste no código com CRUD completo (tenant list/create/get/update/delete), mas não está registado nobin/gaudi-cli.js(comentado). Se for necessário expor a gestão de tenants, basta registarregisterTenant(program). - Renovação de token: o CLI renova o access token manualmente (
auth renew) e automaticamente (daemon start), gravandotokenIssuedAt/tokenExpiresAtna config. Ver a secção "Renovação de token (engenharia)". - O comando
containerfoi removido — a gestão de containers é feita através deworkload.
