@aiuby-ia/cli 0.0.0-stage → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/api.md ADDED
@@ -0,0 +1,115 @@
1
+ # Referência da API do Compute
2
+
3
+ Base: `https://aiuby.com/api/platform/compute`. Respostas em JSON.
4
+
5
+ ## Autenticação
6
+
7
+ - **Leitura (`GET`)**: sessão da área logada, ou `Authorization: Bearer <chave>` com uma chave
8
+ de API de escopo `compute:read`. A chave vale para um workspace.
9
+ - **Escrita (`POST`)**: sessão de uma pessoa com permissão de gerenciar o workspace, ou chave
10
+ de API com o escopo `compute:write`. Limite: 30 alterações por minuto por pessoa ou chave.
11
+ O escopo `compute:write` não inclui leitura: para ler, a chave precisa também de `compute:read`.
12
+
13
+ ## Erros
14
+
15
+ ```json
16
+ { "error": { "code": "compute_not_deployable", "message": "..." } }
17
+ ```
18
+
19
+ `code` aparece só em alguns erros. Status usados: `400` dados inválidos, `401` sem
20
+ autenticação, `403` sem permissão, `404` não encontrado ou Compute não contratado,
21
+ `409` conflito, `429` muitas chamadas.
22
+
23
+ ## Leitura
24
+
25
+ ### `GET /whoami`
26
+
27
+ ```json
28
+ { "organization": "Acme", "workspace": "Principal", "workspaceSlug": "principal",
29
+ "organizationId": "...", "workspaceId": "...", "kind": "credential", "role": null }
30
+ ```
31
+
32
+ ### `GET /apps`
33
+
34
+ ```json
35
+ { "apps": [ { "id": "...", "slug": "minha-api", "name": "Minha API", "currentRevision": 1,
36
+ "archived": false, "createdAt": "2026-11-12T12:00:00.000Z", "runtime": "container",
37
+ "hardwareLabel": "1 vCPU · 512 MB", "region": null } ] }
38
+ ```
39
+
40
+ ### `GET /apps/{ref}`
41
+
42
+ `ref` é o id ou o identificador (slug). Devolve os campos da listagem mais `revisions`:
43
+ `[{ "revision": 1, "createdAt": "...", "config": { ... } }]`. Revisões são imutáveis.
44
+
45
+ ### `GET /apps/{ref}/plan`
46
+
47
+ O plano de implantação da revisão atual. Só leitura.
48
+
49
+ ```json
50
+ { "deployable": false, "provider": null, "sku": null, "preview": false,
51
+ "blockers": ["runtime_not_enabled"],
52
+ "reasons": [ { "code": "runtime_not_enabled", "message": "A execução de aplicações ainda não está habilitada nesta plataforma." } ] }
53
+ ```
54
+
55
+ Bloqueios possíveis: `runtime_not_enabled`, `provider_not_enabled`, `sku_unknown`,
56
+ `gpu_count_unsupported`, `quota_unverified`, `no_rate_card`, `no_budget`, `build_not_supported`,
57
+ `preview_limits`, `preview_capacity`.
58
+
59
+ ### `GET /capacity`
60
+
61
+ `hardware`: o catálogo de referência, cada item com `availability: "unverified"`.
62
+ `providers`: o que cada adaptador de nuvem implementa hoje.
63
+
64
+ ### `GET /templates`
65
+
66
+ `templates`: os modelos de partida, com a configuração inicial de cada um.
67
+
68
+ ## Escrita
69
+
70
+ ### `POST /apps`
71
+
72
+ Cadastra a aplicação com a primeira revisão. Nada é implantado. Responde `201`.
73
+
74
+ ```json
75
+ { "name": "Minha API", "slug": "minha-api",
76
+ "config": { "runtime": "container", "image": "REGISTRO/minha-api:1", "port": 8080,
77
+ "hardware": { "provider": "any", "cpu": 1, "memoryMb": 512 },
78
+ "scaling": { "minReplicas": 0, "maxReplicas": 2 } } }
79
+ ```
80
+
81
+ Regras: `slug` com 3 a 40 caracteres (minúsculas, dígitos e hífen, começando por letra),
82
+ único no workspace; `runtime` `container` exige `image`; campos desconhecidos são recusados.
83
+ Limites: 50 aplicações por workspace, 200 revisões por aplicação.
84
+
85
+ ### `POST /apps/{id}/revisions`
86
+
87
+ Corpo: a nova `config`. Cria uma revisão e a torna a atual. Responde `201`.
88
+
89
+ ### `POST /apps/{id}/archive`
90
+
91
+ Corpo: `{ "archived": true }` ou `false`. Responde `204`.
92
+
93
+ ### `GET /apps/{ref}/deployments`
94
+
95
+ Leitura. A implantação mais recente, já conferida com a conta de nuvem, ou `null`.
96
+
97
+ ```json
98
+ { "deployment": { "id": "...", "revision": 2, "status": "running",
99
+ "url": "https://...run.app", "error": null, "region": "southamerica-east1",
100
+ "createdAt": "...", "expiresAt": "..." } }
101
+ ```
102
+
103
+ `status`: `deploying`, `running`, `failed` ou `stopped`.
104
+
105
+ ### `POST /apps/{ref}/deployments`
106
+
107
+ Sessão de quem gerencia o workspace, ou chave com `compute:deploy`. Implanta a revisão atual.
108
+ Responde `202` com a implantação em `deploying`. Só funciona em organização com a prévia
109
+ do runtime; nas demais, e sempre que o plano tiver bloqueios, responde `409` com
110
+ `code: "compute_not_deployable"` e os motivos. Limites da prévia: CPU, até 1 vCPU e 1 GB,
111
+ 1 réplica, endereço público, com prazo.
112
+
113
+ ### `POST /apps/{ref}/deployments/stop`
114
+
115
+ Mesma autenticação. Apaga o serviço na nuvem e encerra a implantação. Responde `204`.
package/docs/cli.md ADDED
@@ -0,0 +1,98 @@
1
+ # Referência da CLI `aiuby`
2
+
3
+ Versão 0.3.0. A CLI fala só com a API da AIUBY: nunca pede nem usa credenciais da AWS ou
4
+ do Google Cloud.
5
+
6
+ Instalação: `npm install -g https://aiuby.com/cli/aiuby-cli-latest.tgz` (Node.js 20 ou mais novo).
7
+
8
+ ## Autenticação
9
+
10
+ | Comando | O que faz |
11
+ | --- | --- |
12
+ | `aiuby login [--url <endereço>]` | Lê uma chave de API do terminal (sem eco) ou da entrada padrão, confere com a API e guarda |
13
+ | `aiuby logout` | Apaga a chave deste computador |
14
+ | `aiuby whoami` | Mostra organização, workspace e endereço da API |
15
+
16
+ - A chave **nunca** é aceita como argumento, para não ficar no histórico do shell.
17
+ - Fica em `~/.config/aiuby/credentials.json`, com permissão `0600`.
18
+ - Uma chave que a API recusa não é guardada.
19
+ - A API precisa ser HTTPS. HTTP só é aceito em `localhost`.
20
+
21
+ Exemplo sem interação:
22
+
23
+ ```bash
24
+ printf '%s' "$CHAVE" | aiuby login
25
+ ```
26
+
27
+ ## Leitura
28
+
29
+ | Comando | O que faz |
30
+ | --- | --- |
31
+ | `aiuby project list` | O projeto (workspace) da chave em uso |
32
+ | `aiuby apps list` | Aplicações cadastradas no workspace |
33
+ | `aiuby apps status <identificador>` | Detalhe, revisões e plano de uma aplicação |
34
+ | `aiuby capacity list [--provider gcp\|aws]` | Catálogo de hardware. É referência pública: cota, região e preço não foram verificados |
35
+ | `aiuby deploy --dry-run <identificador>` | O plano de implantação, sem criar nada. Sai com código 4 quando há bloqueios |
36
+
37
+ ## Escrita
38
+
39
+ Exigem uma chave com os escopos "Ler o Compute" e "Gerenciar aplicações do Compute".
40
+ Nenhum destes comandos implanta: eles só registram a aplicação e a configuração.
41
+
42
+ | Comando | O que faz |
43
+ | --- | --- |
44
+ | `aiuby apps create [arquivo]` | Cadastra a aplicação descrita no `aiuby.toml` (padrão: o do diretório atual), com a revisão r1 |
45
+ | `aiuby apps update [arquivo]` | Grava a configuração do arquivo como nova revisão da aplicação de mesmo `slug`. Sem mudança, não cria revisão. Não altera o nome |
46
+
47
+ ## Implantação (prévia do runtime)
48
+
49
+ Exigem uma chave com o escopo "Implantar no Compute" e uma organização com a prévia do
50
+ runtime habilitada pela AIUBY. Fora dela, a API recusa com os motivos (código de saída 4).
51
+
52
+ | Comando | O que faz |
53
+ | --- | --- |
54
+ | `aiuby deploy [--no-wait] <identificador>` | Implanta a revisão atual no Google Cloud e acompanha até ficar em execução (até 3 minutos). Mostra o endereço público e o prazo. Reimplantar troca a revisão no mesmo endereço |
55
+ | `aiuby stop <identificador>` | Para a implantação: o serviço é apagado e o endereço deixa de responder |
56
+
57
+ Limites da prévia: só CPU, até 1 vCPU e 1 GB, 1 réplica (escala a zero quando ociosa),
58
+ endereço público sem autenticação, prazo de algumas horas. Sem cobrança nesta fase.
59
+
60
+ ## Local
61
+
62
+ | Comando | O que faz |
63
+ | --- | --- |
64
+ | `aiuby init [template] [diretório]` | Copia um template de partida para um diretório novo ou vazio. Sem argumento, lista os templates |
65
+ | `aiuby config validate [arquivo]` | Valida um `aiuby.toml` (padrão: o do diretório atual). Não usa a rede |
66
+ | `aiuby doctor` | Confere versão do Node.js, credencial, permissão do arquivo e resposta da API |
67
+
68
+ ## Ainda não disponíveis
69
+
70
+ `run`, `logs`, `scale`, `rollback`, `volumes`, `secrets`
71
+ e `domains` respondem que ainda não estão disponíveis e saem com código 4. Nenhum deles chama a API.
72
+
73
+ ## Opções gerais
74
+
75
+ | Opção | Efeito |
76
+ | --- | --- |
77
+ | `--json` | Saída em JSON, para scripts |
78
+ | `--help` | Ajuda |
79
+ | `--version` | Versão |
80
+
81
+ ## Variáveis de ambiente
82
+
83
+ | Variável | Efeito |
84
+ | --- | --- |
85
+ | `AIUBY_TOKEN` | Chave de API. Tem prioridade sobre o arquivo; use em CI |
86
+ | `AIUBY_API_URL` | Endereço da API (padrão `https://aiuby.com`) |
87
+ | `AIUBY_CONFIG_DIR` | Diretório do arquivo de credencial |
88
+
89
+ ## Códigos de saída
90
+
91
+ | Código | Significado |
92
+ | --- | --- |
93
+ | 0 | Sucesso |
94
+ | 1 | Erro (rede, servidor, `doctor` com falha) |
95
+ | 2 | Uso incorreto |
96
+ | 3 | Não autenticado |
97
+ | 4 | Recusado: recurso indisponível, não encontrado, sem permissão ou plano com bloqueios |
98
+ | 5 | Configuração inválida (no arquivo, ou recusada pela API) |
package/package.json CHANGED
@@ -1,6 +1,42 @@
1
1
  {
2
2
  "name": "@aiuby-ia/cli",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.3.0",
4
+ "description": "Linha de comando do AIUBY Compute",
5
+ "type": "module",
6
+ "bin": {
7
+ "aiuby": "dist/aiuby.mjs"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "templates",
12
+ "docs",
13
+ "THIRD_PARTY_LICENSES.md"
14
+ ],
15
+ "engines": {
16
+ "node": ">=20"
17
+ },
18
+ "scripts": {
19
+ "build": "esbuild src/main.ts --bundle --platform=node --target=node20 --format=esm --banner:js='#!/usr/bin/env node' --outfile=dist/aiuby.mjs && chmod +x dist/aiuby.mjs",
20
+ "typecheck": "tsc --noEmit",
21
+ "test": "vitest run",
22
+ "check": "npm run typecheck && npm test && npm run build"
23
+ },
24
+ "devDependencies": {
25
+ "@types/node": "^22.10.0",
26
+ "esbuild": "^0.25.0",
27
+ "smol-toml": "1.3.1",
28
+ "typescript": "^5.7.0",
29
+ "vitest": "^3.0.9",
30
+ "zod": "4.6.7"
31
+ },
32
+ "license": "UNLICENSED",
33
+ "homepage": "https://aiuby.com",
34
+ "keywords": [
35
+ "aiuby",
36
+ "compute",
37
+ "cli"
38
+ ],
39
+ "publishConfig": {
40
+ "access": "public"
41
+ }
42
+ }
@@ -0,0 +1,10 @@
1
+ FROM python:3.12-slim
2
+ WORKDIR /app
3
+ COPY requirements.txt .
4
+ RUN pip install --no-cache-dir -r requirements.txt
5
+ COPY main.py .
6
+ # Usuário sem privilégio: o runtime não deve precisar de root.
7
+ RUN useradd --create-home app
8
+ USER app
9
+ EXPOSE 8080
10
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]
@@ -0,0 +1,17 @@
1
+ # Configuração da aplicação no AIUBY Compute. Valide com: aiuby config validate
2
+ name = "Minha API"
3
+ slug = "minha-api"
4
+
5
+ [config]
6
+ runtime = "container"
7
+ image = "REGISTRO/minha-api:1"
8
+ port = 8080
9
+
10
+ [config.hardware]
11
+ provider = "any"
12
+ cpu = 1
13
+ memoryMb = 512
14
+
15
+ [config.scaling]
16
+ minReplicas = 0
17
+ maxReplicas = 2
@@ -0,0 +1,19 @@
1
+ """API HTTP mínima. Ponto de partida do template "API HTTP com FastAPI" do AIUBY Compute."""
2
+ from fastapi import FastAPI
3
+ from pydantic import BaseModel
4
+
5
+ app = FastAPI(title="minha-api")
6
+
7
+
8
+ class Entrada(BaseModel):
9
+ texto: str
10
+
11
+
12
+ @app.get("/health")
13
+ def health() -> dict[str, str]:
14
+ return {"status": "ok"}
15
+
16
+
17
+ @app.post("/eco")
18
+ def eco(entrada: Entrada) -> dict[str, int | str]:
19
+ return {"texto": entrada.texto, "caracteres": len(entrada.texto)}
@@ -0,0 +1,2 @@
1
+ fastapi>=0.115,<1
2
+ uvicorn[standard]>=0.30,<1
@@ -0,0 +1,10 @@
1
+ FROM python:3.12-slim
2
+ WORKDIR /app
3
+ COPY requirements.txt .
4
+ RUN pip install --no-cache-dir -r requirements.txt
5
+ COPY main.py .
6
+ # Usuário sem privilégio: o runtime não deve precisar de root.
7
+ RUN useradd --create-home app
8
+ USER app
9
+ EXPOSE 8080
10
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]
@@ -0,0 +1,17 @@
1
+ # Agente LangGraph por HTTP. Valide com: aiuby config validate
2
+ name = "Agente LangGraph"
3
+ slug = "agente-langgraph"
4
+
5
+ [config]
6
+ runtime = "container"
7
+ image = "REGISTRO/agente-langgraph:1"
8
+ port = 8080
9
+
10
+ [config.hardware]
11
+ provider = "any"
12
+ cpu = 1
13
+ memoryMb = 1024
14
+
15
+ [config.scaling]
16
+ minReplicas = 0
17
+ maxReplicas = 2
@@ -0,0 +1,40 @@
1
+ """Agente mínimo com LangGraph exposto por HTTP. Sem modelo embutido: o nó "responder"
2
+ é onde entra a chamada ao seu modelo (por exemplo, pelo Gateway da AIUBY)."""
3
+ from typing import TypedDict
4
+
5
+ from fastapi import FastAPI
6
+ from langgraph.graph import END, StateGraph
7
+ from pydantic import BaseModel
8
+
9
+
10
+ class Estado(TypedDict):
11
+ pergunta: str
12
+ resposta: str
13
+
14
+
15
+ def responder(estado: Estado) -> Estado:
16
+ # Troque por uma chamada ao modelo. Aqui só devolve o que recebeu.
17
+ return {"pergunta": estado["pergunta"], "resposta": f"Recebi: {estado['pergunta']}"}
18
+
19
+
20
+ grafo = StateGraph(Estado)
21
+ grafo.add_node("responder", responder)
22
+ grafo.set_entry_point("responder")
23
+ grafo.add_edge("responder", END)
24
+ agente = grafo.compile()
25
+
26
+ app = FastAPI(title="agente-langgraph")
27
+
28
+
29
+ class Entrada(BaseModel):
30
+ pergunta: str
31
+
32
+
33
+ @app.get("/health")
34
+ def health() -> dict[str, str]:
35
+ return {"status": "ok"}
36
+
37
+
38
+ @app.post("/perguntar")
39
+ def perguntar(entrada: Entrada) -> dict[str, str]:
40
+ return dict(agente.invoke({"pergunta": entrada.pergunta, "resposta": ""}))
@@ -0,0 +1,3 @@
1
+ fastapi>=0.115,<1
2
+ uvicorn[standard]>=0.30,<1
3
+ langgraph>=0.2,<1
@@ -0,0 +1,6 @@
1
+ # Servidor compatível com a API da OpenAI sobre vLLM. O modelo é baixado na subida:
2
+ # escolha um que caiba na memória da GPU pedida e cuja licença permita o seu uso.
3
+ FROM vllm/vllm-openai:latest
4
+ ENV MODEL_ID="Qwen/Qwen2.5-1.5B-Instruct"
5
+ EXPOSE 8080
6
+ ENTRYPOINT ["/bin/sh", "-c", "python3 -m vllm.entrypoints.openai.api_server --model \"$MODEL_ID\" --host 0.0.0.0 --port 8080"]
@@ -0,0 +1,21 @@
1
+ # Inferência compatível com OpenAI em GPU. Valide com: aiuby config validate
2
+ name = "Inferência vLLM"
3
+ slug = "inferencia-vllm"
4
+
5
+ [config]
6
+ runtime = "container"
7
+ image = "REGISTRO/inferencia-vllm:1"
8
+ port = 8080
9
+
10
+ [config.hardware]
11
+ provider = "gcp"
12
+ cpu = 4
13
+ memoryMb = 16384
14
+
15
+ [config.hardware.gpu]
16
+ sku = "gcp-cloudrun-l4"
17
+ count = 1
18
+
19
+ [config.scaling]
20
+ minReplicas = 0
21
+ maxReplicas = 1