@nio-cli/cli 0.4.0 → 0.6.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/.env.example +22 -9
- package/README.md +186 -78
- package/dist/adapters/pg/client.js +2 -0
- package/dist/adapters/pg/client.js.map +1 -1
- package/dist/adapters/pg/login-challenge-repository.js.map +1 -1
- package/dist/adapters/sms/whatsapp.js +83 -0
- package/dist/adapters/sms/whatsapp.js.map +1 -0
- package/dist/app/ai-client.js +2 -2
- package/dist/app/ai-client.js.map +1 -1
- package/dist/cli/commands/ai.js +2 -2
- package/dist/cli/commands/ai.js.map +1 -1
- package/dist/cli/commands/auth.js +5 -5
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/config.js +17 -7
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/docs/content.js +80 -11
- package/dist/cli/commands/docs/content.js.map +1 -1
- package/dist/cli/commands/exec.js +1 -12
- package/dist/cli/commands/exec.js.map +1 -1
- package/dist/cli/commands/init/index.js +1 -2
- package/dist/cli/commands/init/index.js.map +1 -1
- package/dist/cli/commands/init/provision-step.js +2 -20
- package/dist/cli/commands/init/provision-step.js.map +1 -1
- package/dist/cli/commands/plan.js +1 -12
- package/dist/cli/commands/plan.js.map +1 -1
- package/dist/cli/commands/security.js +15 -15
- package/dist/cli/commands/security.js.map +1 -1
- package/dist/cli/commands/sync.js +4 -18
- package/dist/cli/commands/sync.js.map +1 -1
- package/dist/cli/commands/validate-plan.js +1 -10
- package/dist/cli/commands/validate-plan.js.map +1 -1
- package/dist/cli/copy/flows.json +1 -2
- package/dist/cli/copy.js.map +1 -1
- package/dist/cli/flows/dependencies.js +0 -4
- package/dist/cli/flows/dependencies.js.map +1 -1
- package/dist/cli/help-guide.js +69 -0
- package/dist/cli/help-guide.js.map +1 -0
- package/dist/cli/program.js +3 -3
- package/dist/cli/program.js.map +1 -1
- package/dist/cli/ui/render.js +0 -27
- package/dist/cli/ui/render.js.map +1 -1
- package/dist/cli.js +10 -2
- package/dist/cli.js.map +1 -1
- package/dist/gateway/services/login.js +6 -7
- package/dist/gateway/services/login.js.map +1 -1
- package/dist/gateway/services/security.js +6 -6
- package/dist/gateway/services/security.js.map +1 -1
- package/dist/lib/auth/gateway-token.js +3 -0
- package/dist/lib/auth/gateway-token.js.map +1 -1
- package/dist/lib/auth/nio-config.js +28 -0
- package/dist/lib/auth/nio-config.js.map +1 -1
- package/dist/lib/clients/client-configs.js +81 -86
- package/dist/lib/clients/client-configs.js.map +1 -1
- package/dist/lib/deps/dependencies.js +0 -25
- package/dist/lib/deps/dependencies.js.map +1 -1
- package/dist/lib/deps/dependency-install.js +3 -23
- package/dist/lib/deps/dependency-install.js.map +1 -1
- package/dist/lib/exec/exec-delegate.js +69 -48
- package/dist/lib/exec/exec-delegate.js.map +1 -1
- package/dist/lib/exec/plan-delegate.js +25 -34
- package/dist/lib/exec/plan-delegate.js.map +1 -1
- package/dist/lib/exec/qwen-client.js +74 -0
- package/dist/lib/exec/qwen-client.js.map +1 -0
- package/dist/lib/exec/validate-plan-delegate.js +13 -30
- package/dist/lib/exec/validate-plan-delegate.js.map +1 -1
- package/dist/lib/provision/provision.js +2 -2
- package/dist/lib/provision/provision.js.map +1 -1
- package/dist/lib/skills/patterns.js +15 -24
- package/dist/lib/skills/patterns.js.map +1 -1
- package/dist/lib/skills/skills.js +1 -1
- package/dist/lib/skills/skills.js.map +1 -1
- package/dist/mcp-server.js +0 -15
- package/dist/mcp-server.js.map +1 -1
- package/dist/tools/delegate-exec.js +3 -10
- package/dist/tools/delegate-exec.js.map +1 -1
- package/dist/tools/plan.js +6 -13
- package/dist/tools/plan.js.map +1 -1
- package/dist/tools/validate-plan.js +6 -14
- package/dist/tools/validate-plan.js.map +1 -1
- package/dist/tui/app.js +102 -18
- package/dist/tui/app.js.map +1 -1
- package/dist/tui/components.js +161 -88
- package/dist/tui/components.js.map +1 -1
- package/dist/tui/launch.js.map +1 -1
- package/dist/tui/opencode.js +27 -0
- package/dist/tui/opencode.js.map +1 -1
- package/dist/tui/palette.js +12 -5
- package/dist/tui/palette.js.map +1 -1
- package/dist/tui/prompt-input.js +168 -0
- package/dist/tui/prompt-input.js.map +1 -0
- package/dist/tui/state.js +252 -20
- package/dist/tui/state.js.map +1 -1
- package/dist/tui/test-utils.js +24 -0
- package/dist/tui/test-utils.js.map +1 -0
- package/package.json +2 -2
- package/dist/adapters/sms/http-generic.js +0 -71
- package/dist/adapters/sms/http-generic.js.map +0 -1
- package/dist/cli/commands/clean.js +0 -108
- package/dist/cli/commands/clean.js.map +0 -1
- package/dist/lib/clients/hooks.js +0 -191
- package/dist/lib/clients/hooks.js.map +0 -1
- package/dist/lib/exec/exec-engines.js +0 -63
- package/dist/lib/exec/exec-engines.js.map +0 -1
package/.env.example
CHANGED
|
@@ -77,18 +77,31 @@ JWT_SECRET=
|
|
|
77
77
|
# Porta do proxy Kong publicada no host pelo `dev:kong` (default 8000).
|
|
78
78
|
# NIO_KONG_PROXY_PORT=8010
|
|
79
79
|
|
|
80
|
-
# 2º fator (
|
|
81
|
-
# responde 503 "2FA não configurado" (o login de
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
#
|
|
80
|
+
# 2º fator (WhatsApp OTP via Meta Graph) — spec 0004 / ADR 0006. Sem endpoint
|
|
81
|
+
# + token, o login com auth_2 responde 503 "2FA não configurado" (o login de
|
|
82
|
+
# 1 fator segue normal).
|
|
83
|
+
# WHATSAPP_ENDPOINT_URL=https://graph.facebook.com/v25.0/1076830002188066/messages
|
|
84
|
+
# WHATSAPP_TOKEN=<bearer da Meta Graph> # app secret; rotaciona ~24h
|
|
85
|
+
# WHATSAPP_TEMPLATE_NAME=autenticao # template de autenticação aprovado
|
|
86
|
+
# WHATSAPP_TEMPLATE_LANGUAGE=pt_BR # variação do template
|
|
86
87
|
#
|
|
87
|
-
# DEV: se
|
|
88
|
-
# `bun run dev:
|
|
88
|
+
# DEV: se WHATSAPP_ENDPOINT_URL for loopback (127.0.0.1/localhost — o mock
|
|
89
|
+
# `bun run dev:whatsapp-echo`), o gateway entra em "modo echo": NENHUM WhatsApp real sai.
|
|
89
90
|
# A CLI avisa e mostra o código direto; `nio security status` mostra o backend.
|
|
90
91
|
|
|
91
|
-
# Client de IA (nio ai) —
|
|
92
|
+
# Client de IA (nio ai) — backend OpenAI-compatível que o provider `opencode`
|
|
93
|
+
# consome (o SDK anexa /chat/completions). Estes são os knobs da "troca" do client.
|
|
94
|
+
# Motor = provider DEDICADO (openai-compatible) direto no backend; o provider `opencode`
|
|
95
|
+
# fica no default (big-pickle), fora do motor da CLI.
|
|
96
|
+
# NIO_AI_PROVIDER=nio-local # id do provider dedicado no opencode.json
|
|
97
|
+
# NIO_AI_BASE_URL=http://192.168.0.140:8001/v1 # backend de IA (default); raiz /v1
|
|
98
|
+
# NIO_AI_MODEL=RedHatAI/Qwen3.8-27B-INT4 # id do model EXATO que o backend serve (sem prefixo de provider)
|
|
99
|
+
# NIO_AI_CONTEXT=65536 # janela de contexto (tokens) declarada p/ o model; 0 = usa catálogo
|
|
100
|
+
# NIO_AI_OUTPUT=2048 # teto de tokens de saída reservados dentro da janela
|
|
101
|
+
# NIO_AI_MAX_INPUT=32000 # hard cap de input por prompt (0 = desativa a trava)
|
|
102
|
+
# ^ NIO_AI_* NÃO valem no .env do projeto (cwd é allowlist) — ponha em ~/.nio/config.env ou no shell.
|
|
103
|
+
#
|
|
104
|
+
# Headroom — proxy de compressão em container (ADR 0007), DORMENTE (ADR 0010).
|
|
92
105
|
# NIO_HEADROOM_PORT=8787 # porta do proxy no host
|
|
93
106
|
# NIO_HEADROOM_URL=http://127.0.0.1:8787/v1 # override total (o provider do OpenCode aponta pra cá)
|
|
94
107
|
# NIO_HEADROOM_OPENAI_TARGET=https://opencode.ai/zen/v1 # upstream OpenAI-compatível (default: OpenCode Zen)
|
package/README.md
CHANGED
|
@@ -5,7 +5,8 @@ responde um wizard, e a CLI — com auxílio de IA via MCP — materializa o amb
|
|
|
5
5
|
toolchains, linguagens, frameworks, dotfiles, aliases e IDE. A entidade central é
|
|
6
6
|
a **Sessão**: um ambiente isolado, com UUID, persistido no Postgres.
|
|
7
7
|
|
|
8
|
-
>
|
|
8
|
+
> **Guia rápido de uso:** `nio --help` (primeiros passos + como usar a interface do `nio ai`).
|
|
9
|
+
> **Manual completo:** `nio docs` no terminal · `nio docs --html --open` como página.
|
|
9
10
|
|
|
10
11
|
---
|
|
11
12
|
|
|
@@ -27,11 +28,14 @@ você → nio (CLI) ──► nio-gateway ──► Postgres (login: senh
|
|
|
27
28
|
`EnvironmentBuilder` garante os toolchains, resolve os MCPs e grava o `config`
|
|
28
29
|
materializado na linha `sessions` do Postgres. A sessão é isolada, tem UUID e
|
|
29
30
|
pode ser reativada depois (`nio sessions`).
|
|
30
|
-
3. **`nio ai` abre a interface NIO** — o
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
3. **`nio ai` abre a interface NIO** — o `opencode serve` headless
|
|
32
|
+
(`opencode/big-pickle`, MCP `nio` + MCPs do perfil) e o chat do NIO em Ink
|
|
33
|
+
(fluxo em linha estilo Claude Code, paleta `/`, `Tab` troca de modo). O
|
|
34
|
+
Headroom foi desativado ([ADR 0010](docs/adr/0010-headroom-desativado.md)) — o
|
|
35
|
+
client fala direto no LLM, **não precisa de Docker**. Com IDE, roda num
|
|
36
|
+
terminal integrado dela. A partir daí o agente tem as tools `nio_*` —
|
|
37
|
+
criar/ativar sessão, re-materializar ambiente, delegar execução. Detalhe de
|
|
38
|
+
uso: **[Interface do `nio ai`](#interface-do-nio-ai-tui)**.
|
|
35
39
|
|
|
36
40
|
O **Postgres é a fonte da verdade** do domínio (usuários, sessões, trilha de
|
|
37
41
|
auth). A CLI e o gateway só falam com o banco que **você** configurar — não há
|
|
@@ -58,7 +62,7 @@ Ficam no PATH: `nio` (CLI), `nio-gateway` (serviço de auth), `nio-cli` e
|
|
|
58
62
|
| **`JWT_SECRET`** (segredo do time) | assinar/validar as sessões | mesmo valor em toda máquina |
|
|
59
63
|
| **OpenCode** | operador de IA | o `nio init` oferece instalar (`npm i -g opencode-ai`) |
|
|
60
64
|
| **Docker** | **não é necessário** pro `nio ai` (Headroom desativado, ADR 0010 — client fala direto no LLM). Ainda usado por `nio docker` (toolkit/cluster) e pelo gateway conteinerizado | `docker compose version` |
|
|
61
|
-
| *(opcional)*
|
|
65
|
+
| *(opcional)* WhatsApp Business API (Meta Graph) | 2º fator | `WHATSAPP_ENDPOINT_URL` + `WHATSAPP_TOKEN` (+ template) |
|
|
62
66
|
|
|
63
67
|
---
|
|
64
68
|
|
|
@@ -89,10 +93,15 @@ NIO_DATABASE_URL=postgres://usuario:senha@HOST:5432/nio_cli
|
|
|
89
93
|
# NIO_DATABASE_SSL=true # só se o banco exigir TLS (gerenciado/nuvem)
|
|
90
94
|
JWT_SECRET=<mesmo-valor-do-time>
|
|
91
95
|
|
|
92
|
-
# 2º fator (
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
#
|
|
96
|
+
# 2º fator (WhatsApp OTP via Meta Graph) — opcional, só no lado do gateway
|
|
97
|
+
# WHATSAPP_ENDPOINT_URL=https://graph.facebook.com/v25.0/1076830002188066/messages
|
|
98
|
+
# WHATSAPP_TOKEN=<bearer da Meta Graph> # app secret; rotaciona ~24h
|
|
99
|
+
# WHATSAPP_TEMPLATE_NAME=autenticao # template de autenticação aprovado
|
|
100
|
+
# WHATSAPP_TEMPLATE_LANGUAGE=pt_BR # variação do template
|
|
101
|
+
#
|
|
102
|
+
# DEV: se WHATSAPP_ENDPOINT_URL for loopback (127.0.0.1/localhost — o mock
|
|
103
|
+
# `bun run dev:whatsapp-echo`), o gateway entra em "modo echo": NENHUM WhatsApp real sai.
|
|
104
|
+
# A CLI avisa e mostra o código direto; `nio security status` mostra o backend.
|
|
96
105
|
```
|
|
97
106
|
|
|
98
107
|
> Alternativa pra time: gere o `~/.nio/config.env` uma vez e distribua o arquivo
|
|
@@ -102,13 +111,32 @@ JWT_SECRET=<mesmo-valor-do-time>
|
|
|
102
111
|
|---|---|---|
|
|
103
112
|
| `NIO_DATABASE_URL` / `NIO_DATABASE_SSL` | `NIO_` | tudo que toca o banco |
|
|
104
113
|
| `JWT_SECRET` / `JWT_EXPIRES_IN` | **sem** prefixo (segredo do time) | `nio-gateway` + `nio-cli` |
|
|
105
|
-
| `
|
|
114
|
+
| `WHATSAPP_ENDPOINT_URL` / `WHATSAPP_TOKEN` (+ `WHATSAPP_TEMPLATE_NAME` / `WHATSAPP_TEMPLATE_LANGUAGE`) | **sem** prefixo | `nio-gateway` |
|
|
106
115
|
| `NIO_GATEWAY_HOST` (default `127.0.0.1`) | `NIO_` | `nio-gateway` — `0.0.0.0` p/ Kong em container |
|
|
107
116
|
| `NIO_GATEWAY_URL` (default `http://127.0.0.1:3000`) | `NIO_` | a CLI acha o nio-gateway (Kong na frente = aponta :8000) |
|
|
108
117
|
|
|
109
118
|
O schema de conexão é sempre `postgres://…`; um destino inválido falha explícito,
|
|
110
119
|
nunca cai num default silencioso.
|
|
111
120
|
|
|
121
|
+
### Backend de IA próprio (uso fora da rede NIO)
|
|
122
|
+
|
|
123
|
+
O motor de IA (`nio ai`/`exec`/`plan`) fala com um backend OpenAI-compatível
|
|
124
|
+
(`/v1`). **O default aponta pra infra interna** (`http://192.168.0.140:8001/v1`,
|
|
125
|
+
modelo `RedHatAI/Qwen3.8-27B-INT4`) — fora dessa rede, suba seu próprio
|
|
126
|
+
vLLM (ou compatível) e aponte a CLI pra ele em `~/.nio/config.env`
|
|
127
|
+
(`nio config path`; `NIO_AI_*` **não** valem no `.env` do projeto):
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
NIO_AI_BASE_URL=https://seu-vllm:8000/v1 # raiz /v1 (o SDK anexa /chat/completions)
|
|
131
|
+
NIO_AI_MODEL=seu-org/seu-modelo # id EXATO que o backend serve em /v1/models
|
|
132
|
+
NIO_AI_CONTEXT=65536 # max_model_len do backend; 0 = usa catálogo
|
|
133
|
+
NIO_AI_OUTPUT=2048 # teto de saída (input + output ≤ contexto!)
|
|
134
|
+
NIO_AI_MAX_INPUT=32000 # trava de input por prompt (0 = desativa)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Confira com `nio config check` — ele sonda `GET <base>/models` e avisa (sem
|
|
138
|
+
reprovar) se o backend está fora do ar ou não serve o modelo configurado.
|
|
139
|
+
|
|
112
140
|
---
|
|
113
141
|
|
|
114
142
|
## Primeiros passos
|
|
@@ -132,7 +160,7 @@ nio-gateway # gateway de auth (a esteira sobe sozinha se faltar)
|
|
|
132
160
|
nio register # cria seu usuário na base compartilhada → cai no login
|
|
133
161
|
nio login # autentica (salva o JWT em ~/.nio/session.json)
|
|
134
162
|
nio security enable-2fa # (opcional) 2º fator
|
|
135
|
-
nio init # monta o ambiente da sessão → `nio ai` (
|
|
163
|
+
nio init # monta o ambiente da sessão → `nio ai` (opencode serve + chat NIO, num terminal da IDE)
|
|
136
164
|
```
|
|
137
165
|
|
|
138
166
|
O `nio-gateway` só é necessário pros comandos de auth (`login`/`logout`/
|
|
@@ -187,29 +215,30 @@ nio whoami # mostra quem está logado (--json pra saída estável)
|
|
|
187
215
|
nio logout # revoga a auth_session no banco e limpa a sessão local
|
|
188
216
|
```
|
|
189
217
|
|
|
190
|
-
### 2º fator (
|
|
218
|
+
### 2º fator (WhatsApp)
|
|
191
219
|
|
|
192
220
|
Opt-in por conta. Com `auth_2` ativo, o `nio login` pede um código de 6 dígitos
|
|
193
|
-
por
|
|
194
|
-
vez no `enable-2fa`).
|
|
221
|
+
enviado por WhatsApp (template de autenticação da Meta Graph); se a mensagem não
|
|
222
|
+
chega, vale um dos 10 **códigos de backup** (mostrados uma vez no `enable-2fa`).
|
|
195
223
|
|
|
196
224
|
```bash
|
|
197
|
-
nio security enable-2fa # cadastra o celular, confirma via
|
|
225
|
+
nio security enable-2fa # cadastra o celular, confirma via WhatsApp, mostra os backups
|
|
198
226
|
nio security status # ativo? número (mascarado)? quantos backups restam?
|
|
199
227
|
nio security disable-2fa
|
|
200
228
|
nio security regenerate-backup-codes
|
|
201
229
|
```
|
|
202
230
|
|
|
203
231
|
O gateway gera/valida o OTP em processo (sem Twilio, sem broker), guarda só o
|
|
204
|
-
**HMAC** do código (TTL 5 min, 3 tentativas, uso único) e manda
|
|
205
|
-
**
|
|
206
|
-
`auth_2` responde `503 "2FA não configurado"` — o login
|
|
232
|
+
**HMAC** do código (TTL 5 min, 3 tentativas, uso único) e manda a mensagem pela
|
|
233
|
+
**WhatsApp Business API (Meta Graph)**. Sem `WHATSAPP_ENDPOINT_URL`/`WHATSAPP_TOKEN`
|
|
234
|
+
no ambiente, o login com `auth_2` responde `503 "2FA não configurado"` — o login
|
|
235
|
+
de 1 fator segue normal.
|
|
207
236
|
Detalhes: [spec 0004](docs/specs/auth/0004-login-2fa-sms-otp.md) ·
|
|
208
237
|
[ADR 0006](docs/adr/0006-2fa-sms-otp.md) ·
|
|
209
238
|
[`docs/arch/ARQUITETURA-GATEWAY.md`](docs/arch/ARQUITETURA-GATEWAY.md).
|
|
210
239
|
|
|
211
|
-
Pra testar sem
|
|
212
|
-
endpoint local que imprime o código no terminal (aponte `
|
|
240
|
+
Pra testar sem WhatsApp real, o repo traz um mock: `bun run dev:whatsapp-echo` sobe
|
|
241
|
+
um endpoint local que imprime o código no terminal (aponte `WHATSAPP_ENDPOINT_URL` pra ele).
|
|
213
242
|
|
|
214
243
|
---
|
|
215
244
|
|
|
@@ -219,19 +248,77 @@ No fim do `nio init` a CLI sobe o **client de IA** da sessão — e o mesmo `nio
|
|
|
219
248
|
retoma a qualquer momento. Ele:
|
|
220
249
|
|
|
221
250
|
1. **Prepara o `opencode.json`** — grava o provider `opencode` **direto no OpenCode Zen**
|
|
222
|
-
(sem `baseURL` de proxy), junto do `model: opencode/big-pickle`, do MCP `nio
|
|
223
|
-
do perfil
|
|
251
|
+
(sem `baseURL` de proxy), junto do `model: opencode/big-pickle`, do MCP `nio`, dos MCPs
|
|
252
|
+
do perfil e de um bloco `permission` semeado (allowlist só-leitura → `allow`, resto →
|
|
253
|
+
`ask`). O **Headroom foi desativado** ([ADR 0010](docs/adr/0010-headroom-desativado.md)):
|
|
224
254
|
o client fala direto no LLM, sem compressão — **não precisa de Docker** pro `nio ai`.
|
|
225
255
|
(O `nio docker headroom` continua existindo, dormente, pra quem quiser subir manualmente.)
|
|
226
|
-
2. **Sobe o `opencode serve` headless e abre a interface NIO** (Ink
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
256
|
+
2. **Sobe o `opencode serve` headless e abre a interface NIO** (Ink). O motor é o
|
|
257
|
+
`opencode/big-pickle`; a casca é nossa. Se a sessão tem IDE (VS Code / Cursor), o
|
|
258
|
+
`nio init` grava um `.vscode/tasks.json` (task `NIO`, `runOn: folderOpen`) e o
|
|
259
|
+
`nio ai` sobe num **terminal integrado da IDE** — uma superfície, não duas. Sem
|
|
260
|
+
IDE, roda no terminal atual. Sem TTY → recusa com mensagem; sem `opencode` no
|
|
261
|
+
PATH → cai na TUI do OpenCode.
|
|
262
|
+
|
|
263
|
+
Ver [`docs/arch/ARQUITETURA-CLIENTE-IA.md`](docs/arch/ARQUITETURA-CLIENTE-IA.md),
|
|
264
|
+
[`docs/arch/ARQUITETURA-TUI-UX-SPRINTS.md`](docs/arch/ARQUITETURA-TUI-UX-SPRINTS.md) e
|
|
265
|
+
[`docs/arch/ARQUITETURA-TUI-INTERACOES-MOTOR.md`](docs/arch/ARQUITETURA-TUI-INTERACOES-MOTOR.md).
|
|
266
|
+
|
|
267
|
+
### Interface do `nio ai` (TUI)
|
|
268
|
+
|
|
269
|
+
Chat no terminal (Ink) sobre o `opencode/big-pickle`, **em uma superfície só** — no
|
|
270
|
+
estilo do Claude Code. O que o motor faz aparece **em linha**, conforme acontece:
|
|
271
|
+
o raciocínio (`✻`), cada ferramenta (`● nome(args)` + `⎿` a saída), o checklist
|
|
272
|
+
(`☑ ◐ ☐`), os arquivos tocados, o diff da rodada (`✎ N arquivo(s) +x −y`) e os
|
|
273
|
+
tokens/custo no rodapé de cada resposta. Sem sidebar, sem janela extra.
|
|
274
|
+
|
|
275
|
+
**Digitar & enviar**
|
|
276
|
+
|
|
277
|
+
| Tecla | Faz |
|
|
278
|
+
|---|---|
|
|
279
|
+
| `Enter` | envia o prompt |
|
|
280
|
+
| `\` + `Enter` · `Ctrl-J` | quebra linha — o prompt é multi-linha e cresce sozinho |
|
|
281
|
+
| `←` `→` `↑` `↓` | move o cursor dentro do texto |
|
|
282
|
+
| `Ctrl-A` / `Ctrl-E` | início / fim da linha |
|
|
283
|
+
| `Ctrl-W` / `Ctrl-U` / `Ctrl-K` | apaga a palavra anterior / até o início / até o fim |
|
|
284
|
+
| colar um bloco | entra literal (várias linhas **não** enviam sozinhas) |
|
|
285
|
+
|
|
286
|
+
**Modos** — o modo troca o comportamento do agente
|
|
287
|
+
|
|
288
|
+
| Tecla | Faz |
|
|
289
|
+
|---|---|
|
|
290
|
+
| `Tab` | alterna entre os agentes primários do `opencode.json` (`build` → `plan` → …) |
|
|
291
|
+
| `build` | o agente **executa** (edita, roda comando) |
|
|
292
|
+
| `plan` | o agente **só propõe** — não toca nada |
|
|
293
|
+
|
|
294
|
+
O modo atual fica no rodapé: `[build]`.
|
|
295
|
+
|
|
296
|
+
**Paleta de comandos**
|
|
297
|
+
|
|
298
|
+
| Tecla | Faz |
|
|
299
|
+
|---|---|
|
|
300
|
+
| `/` | abre a lista inline — comandos do `nio` + capacidades do operador |
|
|
301
|
+
| `↑` `↓` + `Enter` | roda o comando / manda a capacidade pro agente / abre o painel |
|
|
302
|
+
| `Esc` | fecha a lista — o texto que você já digitou **continua lá** |
|
|
303
|
+
|
|
304
|
+
**Quando o agente te interrompe**
|
|
305
|
+
|
|
306
|
+
- **Permissão** (rodar shell, editar arquivo, chamar MCP…) → modal:
|
|
307
|
+
`a`/`Enter` permite uma vez · `s` permite **sempre** (salva a regra no `opencode.json`) · `d`/`Esc` nega.
|
|
308
|
+
Pedidos em paralelo entram numa **fila** (`+N na fila`); um sub-agente travado é
|
|
309
|
+
reconciliado sozinho em ~4s — não trava mais em "processando".
|
|
310
|
+
- **Pergunta aberta** — o agente termina com "?" → o cue `↳ o nio perguntou` aparece acima do input.
|
|
311
|
+
- **Lista de opções** — o agente listou `1./2./3.` → menu `↑`/`↓`+`Enter` pra escolher; ou ignore e escreva livre.
|
|
232
312
|
|
|
233
|
-
|
|
234
|
-
|
|
313
|
+
**Acompanhar & controlar**
|
|
314
|
+
|
|
315
|
+
| Tecla | Faz |
|
|
316
|
+
|---|---|
|
|
317
|
+
| `Ctrl-R` | expande / colapsa o raciocínio (`✻`) — ver o agente "pensar" ao vivo |
|
|
318
|
+
| `Esc` | durante o processamento: **aborta o turno** |
|
|
319
|
+
|
|
320
|
+
`NIO_DEBUG=1 nio ai` grava cada evento cru do motor em `~/.nio/tui.log` (nunca no
|
|
321
|
+
terminal — corromperia o render).
|
|
235
322
|
|
|
236
323
|
> A interface NIO (Ink) está na **fatia 2a** ([ADR 0008](docs/adr/0008-interface-nio-ink.md)).
|
|
237
324
|
> A paridade completa com o OpenCode (diff viewer, file tree, seletor de modelo…) é a 2b.
|
|
@@ -248,19 +335,24 @@ Operações do CLI, **sem o binário na frente** (declarado no cabeçalho da tab
|
|
|
248
335
|
Gerada da fonte por `npm run gen:docs`. Ajuda de qualquer comando: `nio <cmd> --help`.
|
|
249
336
|
|
|
250
337
|
<!-- COMMANDS:START -->
|
|
251
|
-
<!-- gerado por `bun run gen:docs` — não edite à mão. binário `nio`,
|
|
338
|
+
<!-- gerado por `bun run gen:docs` — não edite à mão. binário `nio`, 60 comandos. -->
|
|
252
339
|
|
|
253
340
|
| Comando | Descrição |
|
|
254
341
|
| --- | --- |
|
|
255
|
-
| `
|
|
256
|
-
| `ai
|
|
257
|
-
| `
|
|
342
|
+
| `agents` | Lista os agentes disponíveis |
|
|
343
|
+
| `ai` | Abre a interface NIO da sessão ativa (opencode serve headless + chat Ink) |
|
|
344
|
+
| `ai status` | Estado do Headroom (proxy de compressão — desativado por ADR 0010, dormente) |
|
|
345
|
+
| `command [name]` | Cria um comando personalizado pro operador de IA |
|
|
258
346
|
| `completion [shell]` | Imprime o script de autocomplete (bash\|zsh\|fish). |
|
|
259
347
|
| `config` | Config compartilhada da equipe (~/.nio/config.env) |
|
|
260
348
|
| `config check` | Confere se a config está completa e o Postgres responde |
|
|
261
349
|
| `config path` | Imprime o caminho do arquivo de config |
|
|
262
350
|
| `config setup` | Wizard: cola os valores do time, testa a conexão e salva |
|
|
263
|
-
| `
|
|
351
|
+
| `debug` | Diagnostica o ambiente e aponta onde está o problema |
|
|
352
|
+
| `deps` | Detecta e (opt-in) instala dependências da sessão ativa |
|
|
353
|
+
| `deps scan` | Escaneia os manifests uma vez e registra o que falta |
|
|
354
|
+
| `deps watch` | Escaneia a cada 10s até Ctrl+C |
|
|
355
|
+
| `docker` | Camada Docker: stack NIO, compose, debug e cluster (Swarm) |
|
|
264
356
|
| `docker cluster <action> [arg]` | Docker Swarm — stack `nio-cluster` (up\|down\|status\|scale) |
|
|
265
357
|
| `docker compose <action> [service]` | Wrapper sobre `docker compose` do projeto (up\|down\|restart\|ps\|logs) |
|
|
266
358
|
| `docker create` | Cria e sobe um container (wizard ou flags) |
|
|
@@ -271,28 +363,41 @@ Gerada da fonte por `npm run gen:docs`. Ajuda de qualquer comando: `nio <cmd> --
|
|
|
271
363
|
| `docker headroom up` | Sobe o container do Headroom |
|
|
272
364
|
| `docker orquest [instruction]` | Orquestra os serviços do projeto via compose, dirigido pelo operador (linguagem natural) |
|
|
273
365
|
| `docker portainer` | Abre o Portainer no navegador |
|
|
366
|
+
| `docker stack` | Stack NIO unificado (gateway · kong · headroom · mcp · portainer) — docker/docker-compose.yml |
|
|
367
|
+
| `docker stack down` | Derruba o stack inteiro |
|
|
368
|
+
| `docker stack status` | ps + health dos 5 serviços |
|
|
369
|
+
| `docker stack up` | Sobe o stack inteiro (build do gateway) + registra o MCP |
|
|
274
370
|
| `docker toolkit` | Infra NIO: Docker MCP Gateway + Portainer (docker/docker-compose.yml) |
|
|
275
371
|
| `docker toolkit down` | Derruba a infra e desabilita o MCP no opencode.json |
|
|
276
372
|
| `docker toolkit status` | Estado dos containers + health dos endpoints |
|
|
277
373
|
| `docker toolkit up` | Sobe a infra e registra o gateway no opencode.json |
|
|
278
374
|
| `docs` | Documentação completa da CLI (terminal ou página com --html) |
|
|
279
|
-
| `exec` | Delega a implementação
|
|
375
|
+
| `exec` | Delega a implementação ao Qwen (vLLM local) num worktree e aguarda. |
|
|
280
376
|
| `exec-status <jobId>` | Estado de um job de execução (`nio exec`), em JSON |
|
|
281
377
|
| `init` | Cria nio.json no diretório atual e materializa o ambiente da sessão |
|
|
378
|
+
| `lang` | Conhecimento/config das linguagens (nio-lang) |
|
|
379
|
+
| `lang sync` | Baixa/atualiza o cache de conhecimento das linguagens em ~/.nio/lang |
|
|
282
380
|
| `login` | Autentica via nio-gateway (túnel HTTP) e salva a sessão localmente (JWT) |
|
|
283
381
|
| `logout` | Encerra a sessão local e revoga a auth_session no banco |
|
|
284
|
-
| `
|
|
285
|
-
| `
|
|
286
|
-
| `
|
|
382
|
+
| `open` | Abre a IDE da sessão ativa na pasta do projeto |
|
|
383
|
+
| `plan` | Roda o Qwen (vLLM local) sobre o projeto e escreve/refina o plan.md da raiz. |
|
|
384
|
+
| `register` | Cria um novo usuário via nio-gateway e já entra (login) |
|
|
385
|
+
| `security` | Senha e 2º fator do login (WhatsApp OTP + códigos de backup) |
|
|
386
|
+
| `security change-password` | Troca a senha (exige a senha atual) e encerra todas as sessões |
|
|
287
387
|
| `security disable-2fa` | Desativa o 2º fator |
|
|
288
|
-
| `security enable-2fa` | Ativa o 2º fator via
|
|
388
|
+
| `security enable-2fa` | Ativa o 2º fator via WhatsApp |
|
|
289
389
|
| `security regenerate-backup-codes` | Invalida os códigos de backup e gera 10 novos |
|
|
290
390
|
| `security status` | Mostra o estado do 2º fator |
|
|
391
|
+
| `sessions` | Gerencia as sessões de ambiente (list/activate/pause/delete) |
|
|
392
|
+
| `sessions activate <id>` | Ativa uma sessão (arquiva as demais ativas) |
|
|
393
|
+
| `sessions delete <id>` | Remove uma sessão (irreversível) |
|
|
394
|
+
| `sessions list` | Lista as suas sessões |
|
|
395
|
+
| `sessions pause <id>` | Pausa uma sessão |
|
|
291
396
|
| `skills` | Skills, commands e agents do nio (lidos do repo aberto via cache) |
|
|
292
397
|
| `skills status` | Lista os docs do repo de skills (cache local ~/.nio/skills) |
|
|
293
398
|
| `start` | Conduz a esteira: config → gateway → login → sessão → OpenCode |
|
|
294
399
|
| `sync` | Instala/atualiza skills, commands e agents nos clientes configurados, a partir do bundle (idempotente); checa atualização do pacote |
|
|
295
|
-
| `validate-plan` | Lê o plan.md da raiz e roda o
|
|
400
|
+
| `validate-plan` | Lê o plan.md da raiz e roda o Qwen (vLLM local) para julgar se o plano precisa de uma spec antes de implementar. |
|
|
296
401
|
| `whoami` | Mostra o usuário autenticado |
|
|
297
402
|
<!-- COMMANDS:END -->
|
|
298
403
|
|
|
@@ -355,16 +460,16 @@ O servidor `nio-cli` expõe as tools de ambiente v2 (todas passam pelo
|
|
|
355
460
|
|
|
356
461
|
| Operação | O que faz |
|
|
357
462
|
| --- | --- |
|
|
358
|
-
| `delegate_exec` | Delega a IMPLEMENTAÇÃO
|
|
463
|
+
| `delegate_exec` | Delega a IMPLEMENTAÇÃO ao Qwen (vLLM local, via API — sem assinatura nem binário externo) num worktree já criado pelo /implement. |
|
|
359
464
|
| `env_detect_deps` | Roda UM ciclo do watcher de dependências sobre a pasta da sessão: escaneia os manifests (package.json, requirements.txt, Cargo.toml), detecta o que está declarado mas não instalado e registra um evento por dependência nova (idempotente). |
|
|
360
465
|
| `env_materialize` | Re-materializa o ambiente de uma sessão existente a partir do seu perfil: garante os toolchains de novo, re-resolve os MCPs e reescreve o `config` em `sessions.config`. |
|
|
361
466
|
| `exec_status` | Estado de uma execução delegada (`nio_delegate_exec`): running \| done \| failed, com o resumo do agente, os arquivos alterados e os checks determinísticos (tamanho, lint, build, testes). |
|
|
362
|
-
| `plan` | Roda o
|
|
467
|
+
| `plan` | Roda o Qwen (vLLM local, via API) sobre a raiz do projeto e escreve/refina o `plan.md` de rascunho pré-SDD. |
|
|
363
468
|
| `profile_get` | Consulta o catálogo de perfis de ambiente (hardcoded na CLI). |
|
|
364
469
|
| `session_activate` | Ativa uma sessão de ambiente do usuário por id (o prefixo do UUID basta). |
|
|
365
470
|
| `session_create` | Cria uma sessão de ambiente pro usuário autenticado e materializa o perfil escolhido: garante os toolchains, resolve os MCPs e persiste o `config` em `sessions.config`. |
|
|
366
471
|
| `session_list` | Lista as sessões de ambiente do usuário autenticado (mais recentes primeiro), com id, nome, perfil, status e o `config` materializado. |
|
|
367
|
-
| `validate_plan` | Lê o `plan.md` da raiz do projeto e roda o
|
|
472
|
+
| `validate_plan` | Lê o `plan.md` da raiz do projeto e roda o Qwen (vLLM local, via API) para julgar se o plano é complexo o bastante para virar uma spec SDD antes de implementar. |
|
|
368
473
|
<!-- TOOLS:END -->
|
|
369
474
|
|
|
370
475
|
### Recipes de ambiente (repo NIO-SKILLS)
|
|
@@ -380,13 +485,13 @@ união em linguagens/frameworks/MCPs).
|
|
|
380
485
|
|
|
381
486
|
## Skills, commands e dependências
|
|
382
487
|
|
|
383
|
-
Além das tools, o nio entrega skills
|
|
488
|
+
Além das tools, o nio entrega **skills, commands e agents** pros clientes. O conteúdo
|
|
384
489
|
vive num **repo aberto** — [`hugoreiis12-png/NIO-SKILLS-`](https://github.com/hugoreiis12-png/NIO-SKILLS-) —
|
|
385
490
|
e **não** é um pacote npm. O CLI baixa o repo (zipball do GitHub, sem precisar de `git`)
|
|
386
491
|
pra um cache local em **`~/.nio/skills`** e lê de lá. `nio sync` **atualiza o cache**
|
|
387
492
|
(pull da branch) toda vez, então as skills evoluem sem republicar o CLI; e **auto-detecta**
|
|
388
|
-
|
|
389
|
-
perfil/área do `nio.json`.
|
|
493
|
+
se o OpenCode tem o conector `nio` configurado, provisionando pra ele conforme a seleção
|
|
494
|
+
de perfil/área do `nio.json`.
|
|
390
495
|
|
|
391
496
|
Overrides por ambiente:
|
|
392
497
|
|
|
@@ -400,13 +505,8 @@ Cada cliente recebe no formato que entende:
|
|
|
400
505
|
|
|
401
506
|
| Cliente | Onde | Formato |
|
|
402
507
|
| --------------- | ----------------------------- | ----------------------------------------------------------------------- |
|
|
403
|
-
|
|
|
404
|
-
|
|
|
405
|
-
| Cowork/Desktop | — | via **MCP prompts** + resources, servidos ao vivo (ignora `~/.claude`) |
|
|
406
|
-
|
|
407
|
-
> Configurar o Codex grava `NIO_CLIENT=codex` no `config.toml`, o que faz o servidor
|
|
408
|
-
> provisionar pra `~/.codex` e filtrar os docs pelo surface `codex`. Reinicie o cliente
|
|
409
|
-
> depois do sync pra carregar skills/prompts novos.
|
|
508
|
+
| OpenCode | `~/.config/opencode/` | MCP `nio` registrado no `opencode.json`; skills/commands no layout cru do pacote (`skills/<id>/SKILL.md`) |
|
|
509
|
+
| Cowork/Desktop | — | via **MCP prompts** + resources, servidos ao vivo |
|
|
410
510
|
|
|
411
511
|
> **Como aparecem no Cowork/Claude Desktop.** Lá as skills chegam como **prompts MCP**,
|
|
412
512
|
> que o app expõe como **slash-commands** no menu de conectores/"+" (ex.: digite `/` e
|
|
@@ -419,12 +519,12 @@ Cada cliente recebe no formato que entende:
|
|
|
419
519
|
Um doc pode ser restrito a clientes específicos via frontmatter:
|
|
420
520
|
|
|
421
521
|
```yaml
|
|
422
|
-
clients:
|
|
522
|
+
clients: cowork, opencode # vazio/ausente = todos os clientes
|
|
423
523
|
```
|
|
424
524
|
|
|
425
|
-
Valores: `
|
|
426
|
-
marcado `cowork`
|
|
427
|
-
|
|
525
|
+
Valores: `cowork`, `opencode`. O MCP filtra por esse campo, então um skill
|
|
526
|
+
marcado `cowork` só aparece como prompt no Cowork/Desktop, e um `opencode` só
|
|
527
|
+
nos docs provisionados ao operador OpenCode.
|
|
428
528
|
|
|
429
529
|
### Dependências externas
|
|
430
530
|
|
|
@@ -434,8 +534,8 @@ Commands/skills podem depender de libs externas, declaradas como arquivos em
|
|
|
434
534
|
|
|
435
535
|
- **instalador estruturado** (`npm:`, `skills:` = `npx skills add`, `git:`) → oferece
|
|
436
536
|
rodar com `[y/N]` (comando montado a partir do campo validado, **sem shell**);
|
|
437
|
-
- **`manual:`** (
|
|
438
|
-
|
|
537
|
+
- **`manual:`** (sem instalador automatizável — checagem/UI no cliente) → imprime os
|
|
538
|
+
passos, com os comandos destacados.
|
|
439
539
|
|
|
440
540
|
A string `install:` (se houver) é **só exibição** — nunca é executada. A CLI **detecta
|
|
441
541
|
o que já está instalado** e mostra um selo `✓ instalada` (via `npm ls -g`, dir de
|
|
@@ -445,15 +545,14 @@ destino, ou o `detect:` do frontmatter).
|
|
|
445
545
|
|
|
446
546
|
## Claude Desktop / Cowork
|
|
447
547
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
esse config
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
Configurações avançadas → "Extension Developer" → "Install Extension…".
|
|
548
|
+
O Cowork/Claude Desktop é um cliente de **chat** via MCP — as skills chegam como
|
|
549
|
+
**prompts MCP** servidos ao vivo, e o conector vive no `claude_desktop_config.json`
|
|
550
|
+
com caminhos absolutos (`node` + `dist/mcp-server.js`) e `NIO_CLIENT=cowork`. Ele
|
|
551
|
+
**não** é mais um alvo do `nio init` (o checkbox só oferece OpenCode): o setup
|
|
552
|
+
inicial do conector é manual. O `nio sync` **reafirma** esse config quando o conector
|
|
553
|
+
já existe — com o app instalado e você logado (`nio login`), ele reescreve o entry
|
|
554
|
+
com paths atuais (merge não-destrutivo + backup). Reinicie o Claude Desktop pra
|
|
555
|
+
carregar prompts novos depois do sync.
|
|
457
556
|
|
|
458
557
|
---
|
|
459
558
|
|
|
@@ -478,11 +577,12 @@ background em qualquer comando (`update-notifier`).
|
|
|
478
577
|
| `Não consegui falar com o nio-gateway` | o `nio-gateway` não está no ar — rode `nio-gateway &` |
|
|
479
578
|
| `Não autenticado` | `nio register` (1ª vez) e depois `nio login` |
|
|
480
579
|
| Erro de conexão com o banco | `ECONNREFUSED` = Postgres fora do ar / host errado; `password authentication failed` = credencial; erro de SSL = `NIO_DATABASE_SSL=true` |
|
|
481
|
-
| `2FA não configurado no servidor` (503) | faltam as `
|
|
482
|
-
|
|
|
580
|
+
| `2FA não configurado no servidor` (503) | faltam as `WHATSAPP_*` no ambiente do `nio-gateway` |
|
|
581
|
+
| `nio ai` diz `precisa de um terminal interativo` | você está num pipe/CI — rode num terminal de verdade |
|
|
582
|
+
| `nio ai` travado em "processando" | `Esc` aborta o turno; o motor recupera permissão perdida sozinho em ~4s. Persistiu? `NIO_DEBUG=1 nio ai` e veja `~/.nio/tui.log` |
|
|
583
|
+
| `nio ai` cai na TUI do OpenCode | falta o binário `opencode` no PATH — `npm i -g opencode-ai` |
|
|
483
584
|
| Skills não aparecem no Cowork | chegam como **prompts MCP** (slash-commands), não skills autônomas. Cmd+Q e reabra; confirme o conector |
|
|
484
585
|
| `Conteúdo de skills não encontrado` | cache `~/.nio/skills` vazio — rode `nio sync` com rede, ou `NIO_SKILLS_DIR` pra um checkout local |
|
|
485
|
-
| Sobraram comandos antigos | `nio clean-legacy` (`--dry-run` pra revisar antes) |
|
|
486
586
|
|
|
487
587
|
Sempre: `nio debug` mostra o estado de tudo com uma dica por item. E
|
|
488
588
|
`NIO_DEBUG=1 nio <cmd>` liga log verboso (`[nio:debug]` em stderr): `.env`
|
|
@@ -507,7 +607,15 @@ O logo Matrix anima (chuva caindo) toda vez que aparece em terminal interativo.
|
|
|
507
607
|
|
|
508
608
|
## Versão
|
|
509
609
|
|
|
510
|
-
**0.
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
610
|
+
**0.5.0** — a interface do `nio ai` (TUI) fechada: editor multi-linha, fluxo em
|
|
611
|
+
linha estilo Claude Code (raciocínio, ferramentas, checklist, diff, tokens),
|
|
612
|
+
`Tab` troca de modo, paleta `/` executável, fila de permissões (com recuperação
|
|
613
|
+
de pedido perdido de sub-agente), perguntas e menus de opção. Mais o fix da cauda
|
|
614
|
+
de 30s no shutdown que tocava o Postgres.
|
|
615
|
+
|
|
616
|
+
Base (0.2.0–0.4.0): auth (senha + 2º fator SMS OTP), backend de sessões no
|
|
617
|
+
Postgres, wizard de ambiente, tools MCP, camada Docker, gateway com Kong e a
|
|
618
|
+
auditoria de segurança (argon2id + pepper, HIBP k-anonymity, roles de menor
|
|
619
|
+
privilégio). Nasceu de um cliente NOS/Supabase (v1), já removido.
|
|
620
|
+
|
|
621
|
+
Histórico cronológico: [`docs/PROGRESSO.md`](docs/PROGRESSO.md).
|
|
@@ -38,6 +38,7 @@ let pool = null;
|
|
|
38
38
|
export function getPool() {
|
|
39
39
|
if (pool)
|
|
40
40
|
return pool;
|
|
41
|
+
globalThis.__nioPgPoolOpen = true;
|
|
41
42
|
pool = new Pool({
|
|
42
43
|
connectionString: readDatabaseUrl(),
|
|
43
44
|
ssl: readSslOption(),
|
|
@@ -87,6 +88,7 @@ export async function closePool() {
|
|
|
87
88
|
return;
|
|
88
89
|
const p = pool;
|
|
89
90
|
pool = null;
|
|
91
|
+
globalThis.__nioPgPoolOpen = false;
|
|
90
92
|
await p.end();
|
|
91
93
|
}
|
|
92
94
|
//# sourceMappingURL=client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/adapters/pg/client.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAA0D,MAAM,IAAI,CAAC;AAGlF,SAAS,eAAe;IACtB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,EAAE,CAAC;IACjD,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CACb,uEAAuE;YACrE,4DAA4D,CAC/D,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CACb,gEAAgE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CACtF,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAGD,SAAS,OAAO,CAAC,IAAY;IAC3B,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAClD,OAAO,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,GAAG,CAAC;AACnC,CAAC;AAYD,MAAM,UAAU,aAAa;IAC3B,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC;QAAE,OAAO,SAAS,CAAC;IAEnD,IAAI,OAAO,CAAC,2BAA2B,CAAC,EAAE,CAAC;QACzC,OAAO,CAAC,KAAK,CACX,gFAAgF;YAC9E,iFAAiF,CACpF,CAAC;QACF,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC;IACvC,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,EAAE,CAAC;IACnD,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,CAAC;YACH,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAE,EAAE,EAAE,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;QACxE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,uCAAuC,MAAM,OAAQ,GAAa,CAAC,OAAO,EAAE,CAC7E,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC;AACtC,CAAC;AAED,IAAI,IAAI,GAAgB,IAAI,CAAC;AAM7B,MAAM,UAAU,OAAO;IACrB,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/adapters/pg/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login-challenge-repository.js","sourceRoot":"","sources":["../../../src/adapters/pg/login-challenge-repository.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAe7D,MAAM,IAAI,GACR,yFAAyF,CAAC;AAG5F,MAAM,UAAU,aAAa,CAAC,EAAU;IACtC,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,GAAsB;IACzD,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;QAC3B,OAAO,EAAE,GAAG,CAAC,OAA2B;QACxC,QAAQ,EAAE,GAAG,CAAC,SAAS;QACvB,OAAO,EAAE,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"login-challenge-repository.js","sourceRoot":"","sources":["../../../src/adapters/pg/login-challenge-repository.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAe7D,MAAM,IAAI,GACR,yFAAyF,CAAC;AAG5F,MAAM,UAAU,aAAa,CAAC,EAAU;IACtC,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,GAAsB;IACzD,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;QAC3B,OAAO,EAAE,GAAG,CAAC,OAA2B;QACxC,QAAQ,EAAE,GAAG,CAAC,SAAS;QACvB,OAAO,EAAE,GAAG,CAAC,OAAqB;QAClC,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC9B,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,UAAU,EAAE,GAAG,CAAC,WAAW;QAC3B,SAAS,EAAE,GAAG,CAAC,UAAU;KAC1B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,8BAA8B;IAC5C,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,KAA6B;YACxC,OAAO,eAAe,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;gBAClC,MAAM,EAAE,CAAC,KAAK,CAAC,uDAAuD,CAAC,CAAC;gBACxE,MAAM,EAAE,CAAC,KAAK,CACZ,yEAAyE,EACzE,CAAC,KAAK,CAAC,MAAM,CAAC,CACf,CAAC;gBACF,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,KAAK,CACxB;;uBAEa,IAAI,EAAE,EACnB,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAC9E,CAAC;gBACF,OAAO,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,CAAC;YAC5C,CAAC,CAAC,CAAC;QACL,CAAC;QAED,KAAK,CAAC,QAAQ,CAAC,EAAE;YACf,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;gBAAE,OAAO,IAAI,CAAC;YACpC,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,UAAU,IAAI,sCAAsC,EACpD,CAAC,EAAE,CAAC,CACL,CAAC;YACF,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACxB,OAAO,GAAG,CAAC,CAAC,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAChD,CAAC;QAED,KAAK,CAAC,iBAAiB,CAAC,EAAE;YACxB,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;gBAAE,OAAO,CAAC,CAAC;YACjC,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,sFAAsF,EACtF,CAAC,EAAE,CAAC,CACL,CAAC;YACF,OAAO,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,IAAI,CAAC,CAAC,CAAC;QAC5C,CAAC;QAED,KAAK,CAAC,OAAO,CAAC,EAAE;YACd,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;gBAAE,OAAO;YAC/B,MAAM,KAAK,CACT,uFAAuF,EACvF,CAAC,EAAE,CAAC,CACL,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,aAAa;YACjB,MAAM,KAAK,CAAC,uDAAuD,CAAC,CAAC;QACvE,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export function formatWhatsAppNumber(phone) {
|
|
2
|
+
return phone.replace(/^\+/, '');
|
|
3
|
+
}
|
|
4
|
+
export function buildPayload(phone, code, env = {}) {
|
|
5
|
+
const payload = {
|
|
6
|
+
messaging_product: 'whatsapp',
|
|
7
|
+
to: formatWhatsAppNumber(phone),
|
|
8
|
+
type: 'template',
|
|
9
|
+
template: {
|
|
10
|
+
name: env.templateName ?? 'autenticao',
|
|
11
|
+
language: { code: env.templateLanguage ?? 'pt_BR' },
|
|
12
|
+
components: [
|
|
13
|
+
{
|
|
14
|
+
type: 'body',
|
|
15
|
+
parameters: [{ type: 'text', text: code }],
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
type: 'button',
|
|
19
|
+
sub_type: 'url',
|
|
20
|
+
index: '0',
|
|
21
|
+
parameters: [{ type: 'text', text: code }],
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
return JSON.stringify(payload);
|
|
27
|
+
}
|
|
28
|
+
function readEnv() {
|
|
29
|
+
return {
|
|
30
|
+
url: process.env.WHATSAPP_ENDPOINT_URL?.trim(),
|
|
31
|
+
token: process.env.WHATSAPP_TOKEN?.trim(),
|
|
32
|
+
templateName: process.env.WHATSAPP_TEMPLATE_NAME?.trim(),
|
|
33
|
+
templateLanguage: process.env.WHATSAPP_TEMPLATE_LANGUAGE?.trim(),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '::1', '[::1]', '0.0.0.0']);
|
|
37
|
+
export function smsMode(env = readEnv()) {
|
|
38
|
+
if (!env.url || !env.token)
|
|
39
|
+
return 'unconfigured';
|
|
40
|
+
try {
|
|
41
|
+
return LOOPBACK_HOSTS.has(new URL(env.url).hostname) ? 'echo' : 'provider';
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return 'provider';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export function smsProviderHost(env = readEnv()) {
|
|
48
|
+
if (!env.url)
|
|
49
|
+
return null;
|
|
50
|
+
try {
|
|
51
|
+
return new URL(env.url).hostname;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export function createWhatsAppSender(env = readEnv()) {
|
|
58
|
+
return {
|
|
59
|
+
async sendOtp(to, code) {
|
|
60
|
+
if (!env.url || !env.token) {
|
|
61
|
+
return { status: 'skipped', error: 'WHATSAPP_ENDPOINT_URL / WHATSAPP_TOKEN não configurados' };
|
|
62
|
+
}
|
|
63
|
+
const body = buildPayload(to, code, env);
|
|
64
|
+
try {
|
|
65
|
+
const res = await fetch(env.url, {
|
|
66
|
+
method: 'POST',
|
|
67
|
+
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${env.token}` },
|
|
68
|
+
body,
|
|
69
|
+
signal: AbortSignal.timeout(10_000),
|
|
70
|
+
});
|
|
71
|
+
if (!res.ok) {
|
|
72
|
+
const detail = (await res.text().catch(() => '')).slice(0, 300);
|
|
73
|
+
return { status: 'failed', error: `WhatsApp respondeu ${res.status} ${detail}`.trim() };
|
|
74
|
+
}
|
|
75
|
+
return { status: 'sent' };
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
return { status: 'failed', error: err.message };
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=whatsapp.js.map
|