@neetru/cli 2.7.5 → 2.8.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/CHANGELOG.md +220 -220
- package/README.md +137 -137
- package/dist/cli-kit/format.d.ts +49 -0
- package/dist/cli-kit/format.js +88 -0
- package/dist/cli-kit/format.js.map +1 -0
- package/dist/cli-kit/glyphs.d.ts +22 -0
- package/dist/cli-kit/glyphs.js +22 -0
- package/dist/cli-kit/glyphs.js.map +1 -0
- package/dist/cli-kit/index.d.ts +13 -0
- package/dist/cli-kit/index.js +12 -0
- package/dist/cli-kit/index.js.map +1 -0
- package/dist/cli-kit/palette.d.ts +10 -0
- package/dist/cli-kit/palette.js +36 -0
- package/dist/cli-kit/palette.js.map +1 -0
- package/dist/commands/ai.js +8 -8
- package/dist/commands/autocomplete.js +34 -34
- package/dist/commands/db.d.ts +87 -7
- package/dist/commands/db.js +697 -126
- package/dist/commands/db.js.map +1 -1
- package/dist/commands/deploy.d.ts +5 -0
- package/dist/commands/deploy.js +68 -0
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts +68 -0
- package/dist/commands/dev.js +345 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/init.js +121 -121
- package/dist/commands/new.d.ts +6 -0
- package/dist/commands/new.js +31 -10
- package/dist/commands/new.js.map +1 -1
- package/dist/commands/products-db.d.ts +1 -1
- package/dist/commands/products-db.js +17 -4
- package/dist/commands/products-db.js.map +1 -1
- package/dist/index.js +258 -42
- package/dist/index.js.map +1 -1
- package/dist/lib/ai/context.js +90 -90
- package/dist/lib/db-local/db-json.d.ts +63 -0
- package/dist/lib/db-local/db-json.js +189 -0
- package/dist/lib/db-local/db-json.js.map +1 -0
- package/dist/lib/db-local/env.d.ts +26 -0
- package/dist/lib/db-local/env.js +64 -0
- package/dist/lib/db-local/env.js.map +1 -0
- package/dist/lib/db-local/fingerprint.d.ts +8 -0
- package/dist/lib/db-local/fingerprint.js +28 -0
- package/dist/lib/db-local/fingerprint.js.map +1 -0
- package/dist/lib/db-local/index.d.ts +15 -0
- package/dist/lib/db-local/index.js +14 -0
- package/dist/lib/db-local/index.js.map +1 -0
- package/dist/lib/db-pipeline/build-deps.d.ts +14 -0
- package/dist/lib/db-pipeline/build-deps.js +158 -0
- package/dist/lib/db-pipeline/build-deps.js.map +1 -0
- package/dist/lib/db-pipeline/errors.d.ts +29 -0
- package/dist/lib/db-pipeline/errors.js +29 -0
- package/dist/lib/db-pipeline/errors.js.map +1 -0
- package/dist/lib/db-pipeline/index.d.ts +26 -0
- package/dist/lib/db-pipeline/index.js +25 -0
- package/dist/lib/db-pipeline/index.js.map +1 -0
- package/dist/lib/db-pipeline/pipeline.d.ts +13 -0
- package/dist/lib/db-pipeline/pipeline.js +119 -0
- package/dist/lib/db-pipeline/pipeline.js.map +1 -0
- package/dist/lib/db-pipeline/rehearse.d.ts +99 -0
- package/dist/lib/db-pipeline/rehearse.js +219 -0
- package/dist/lib/db-pipeline/rehearse.js.map +1 -0
- package/dist/lib/db-pipeline/types.d.ts +112 -0
- package/dist/lib/db-pipeline/types.js +20 -0
- package/dist/lib/db-pipeline/types.js.map +1 -0
- package/package.json +63 -62
- package/templates/auth/callback.ts +22 -22
- package/templates/auth/sign-in.tsx +41 -41
- package/templates/billing/checkout.ts +22 -22
- package/templates/billing/page.tsx +43 -43
- package/templates/support/ticket-form.tsx +68 -68
- package/templates/usage/track.ts +30 -30
- package/templates/users/profile.tsx +43 -43
package/README.md
CHANGED
|
@@ -1,137 +1,137 @@
|
|
|
1
|
-
# @neetru/cli
|
|
2
|
-
|
|
3
|
-
> 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.
|
|
4
|
-
|
|
5
|
-
<p>
|
|
6
|
-
<img alt="npm" src="https://img.shields.io/npm/v/@neetru/cli?logo=npm">
|
|
7
|
-
<img alt="downloads" src="https://img.shields.io/npm/dm/@neetru/cli?logo=npm">
|
|
8
|
-
<img alt="Node" src="https://img.shields.io/badge/node-%3E%3D22-339933?logo=node.js&logoColor=white">
|
|
9
|
-
<img alt="license" src="https://img.shields.io/badge/license-MIT-22c55e">
|
|
10
|
-
</p>
|
|
11
|
-
|
|
12
|
-
## Instalação
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
npm install -g @neetru/cli
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
Bootstrap completo da máquina dev (Node, gcloud, Docker, Firebase CLI, deps NPM, GCP ADC):
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
neetru bootstrap
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
Login no Core via OAuth Device Code Flow:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
neetru login
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
Validar estado:
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
neetru doctor
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Quickstart — criar produto SaaS novo
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
neetru new gestovendas --env=dev --tier=dev --customer=neetru
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Cria produto + workspace + scaffold local Next.js 15 + instala deps + abre cockpit no browser.
|
|
43
|
-
|
|
44
|
-
## Comandos principais
|
|
45
|
-
|
|
46
|
-
| Comando | O que faz |
|
|
47
|
-
|---|---|
|
|
48
|
-
| `neetru bootstrap` | Setup da máquina dev (binários + deps + ADC) |
|
|
49
|
-
| `neetru login` / `logout` / `whoami` | Auth OAuth Device Code Flow |
|
|
50
|
-
| `neetru doctor` | Diagnóstico saúde (5 checks rápidos) |
|
|
51
|
-
| `neetru new <slug>` | Criar produto completo (registry + workspace + scaffold) |
|
|
52
|
-
| `neetru init <name>` | Só scaffold local Next.js + Firebase |
|
|
53
|
-
| `neetru add <feature>` | Adicionar features ao scaffold (auth, billing, etc) |
|
|
54
|
-
| `neetru deploy` | Pipeline de deploy interativo (cloud-run / vm / workspace) |
|
|
55
|
-
| `neetru build` | Empacotar produto em tarball pra deploy |
|
|
56
|
-
| `neetru promote` | Promover dev → staging → prod |
|
|
57
|
-
| `neetru env switch <target>` | Trocar `NEETRU_ENV` no `.env.local` |
|
|
58
|
-
| `neetru env set --service=X --set KEY=VAL` | Setar env vars de serviço Cloud Run |
|
|
59
|
-
| `neetru ar create <name>` | Criar repositório Artifact Registry |
|
|
60
|
-
| `neetru hosting create-mapping --service=X --domain=Y` | Domain mapping |
|
|
61
|
-
| `neetru db create --product=X --engine=postgres` | Criar banco por produto |
|
|
62
|
-
| `neetru db engines` | Listar engines disponíveis (firestore, postgres, mysql) |
|
|
63
|
-
| `neetru cloud-run pause/resume/delete <service>` | Controle Cloud Run |
|
|
64
|
-
| `neetru products list/create/update` | Registry de produtos |
|
|
65
|
-
| `neetru workspaces create/list/get/advance` | Instâncias por cliente |
|
|
66
|
-
| `neetru deployments create/rollback` | Histórico de deploys |
|
|
67
|
-
| `neetru tenants list/create/update/suspend` | Gerenciar tenants |
|
|
68
|
-
| `neetru audit tail` | Tail de `audit_logs/` em tempo real |
|
|
69
|
-
| `neetru billing summary` | Resumo de billing |
|
|
70
|
-
| `neetru servers list/provision/deactivate` | Gerenciar servidores |
|
|
71
|
-
| `neetru agent release/yank/canary` | Gerenciar releases do agente |
|
|
72
|
-
| `neetru support tickets list/reply/assign` | Suporte inbox staff |
|
|
73
|
-
| `neetru dns zones list` / `hosting list` | Listar DNS + customer domains |
|
|
74
|
-
| `neetru builds list` | Listar Cloud Build |
|
|
75
|
-
| `neetru dr exports/restore` | Disaster Recovery |
|
|
76
|
-
| `neetru logs` | Ver logs de produtos |
|
|
77
|
-
| `neetru status` | Visão geral do ecossistema |
|
|
78
|
-
| `neetru open <produto>` | Abrir cockpit do produto no browser |
|
|
79
|
-
| `neetru ai` | REPL IA Neetru-aware (Claude/OpenAI/Gemini) |
|
|
80
|
-
| `neetru ui` | Menu interativo do CLI |
|
|
81
|
-
| `neetru publish` | Publicar produto no catálogo público |
|
|
82
|
-
| `neetru fn deploy` | Deploy de Cloud Functions |
|
|
83
|
-
| `neetru upgrade` | Auto-update do CLI |
|
|
84
|
-
| `neetru autocomplete <bash\|zsh\|pwsh>` | Gerar script autocomplete |
|
|
85
|
-
|
|
86
|
-
**Atalhos:** `neetru ar` = `artifact-registry`, `neetru menu` = `ui`.
|
|
87
|
-
|
|
88
|
-
40+ subcomandos. Quase todos suportam `--json` pra automação.
|
|
89
|
-
|
|
90
|
-
## Configuração
|
|
91
|
-
|
|
92
|
-
Config persiste em `~/.config/neetru-cli/` (Linux/macOS) ou `%APPDATA%\neetru-cli\` (Windows):
|
|
93
|
-
|
|
94
|
-
| Chave | Valor |
|
|
95
|
-
|---|---|
|
|
96
|
-
| `neetruApiKey` | Token Bearer `nrt_<keyId>_<secret>` (gerado por `neetru login`) |
|
|
97
|
-
| `coreUrl` | URL base do Core (default `https://core.neetru.com`) |
|
|
98
|
-
| `telemetry.enabled` | Telemetry opt-in (default `false`) |
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
neetru config set telemetry.enabled true
|
|
102
|
-
neetru config get coreUrl
|
|
103
|
-
neetru config path # mostra caminho do config file
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
## Output JSON
|
|
107
|
-
|
|
108
|
-
```bash
|
|
109
|
-
neetru products list --json | jq '.[] | select(.status == "ativo")'
|
|
110
|
-
neetru audit tail --json | jq 'select(.action | startswith("billing"))'
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
## Auth & Segurança
|
|
114
|
-
|
|
115
|
-
- **OAuth Device Code Flow** (RFC 8628) pra login interativo — não armazena password
|
|
116
|
-
- **Tokens** salvos em `conf` cross-platform, permissões 0600 em Unix
|
|
117
|
-
- **Rate-limit** por método HTTP: GET 120/min, POST/PUT/PATCH 30/min, DELETE 5/min
|
|
118
|
-
- **Step-up MFA** (TOTP) obrigatório em operações destrutivas: `--mfa-token <code>` ou prompt
|
|
119
|
-
- **Dry-run** disponível em comandos de mutação: `--dry-run` mostra efeito SEM aplicar
|
|
120
|
-
|
|
121
|
-
## Stack
|
|
122
|
-
|
|
123
|
-
- TypeScript 5 ESM-first
|
|
124
|
-
- Node 22+ (LTS)
|
|
125
|
-
- Sem `node-fetch`/`axios`: fetch global nativo
|
|
126
|
-
- Commander 11 (CLI framework) + Inquirer 12 (prompts) + Chalk 5 + Ora (spinners)
|
|
127
|
-
|
|
128
|
-
## Mais info
|
|
129
|
-
|
|
130
|
-
- **Repo:** [github.com/Neetru/neetru-core](https://github.com/Neetru/neetru-core)
|
|
131
|
-
- **Docs:** [docs.neetru.com](https://docs.neetru.com)
|
|
132
|
-
- **SDK complementar:** `npm install @neetru/sdk`
|
|
133
|
-
- **Issues / suporte:** abrir issue no repo ou `neetru support`
|
|
134
|
-
|
|
135
|
-
## Licença
|
|
136
|
-
|
|
137
|
-
MIT © Neetru
|
|
1
|
+
# @neetru/cli
|
|
2
|
+
|
|
3
|
+
> 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.
|
|
4
|
+
|
|
5
|
+
<p>
|
|
6
|
+
<img alt="npm" src="https://img.shields.io/npm/v/@neetru/cli?logo=npm">
|
|
7
|
+
<img alt="downloads" src="https://img.shields.io/npm/dm/@neetru/cli?logo=npm">
|
|
8
|
+
<img alt="Node" src="https://img.shields.io/badge/node-%3E%3D22-339933?logo=node.js&logoColor=white">
|
|
9
|
+
<img alt="license" src="https://img.shields.io/badge/license-MIT-22c55e">
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
## Instalação
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install -g @neetru/cli
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Bootstrap completo da máquina dev (Node, gcloud, Docker, Firebase CLI, deps NPM, GCP ADC):
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
neetru bootstrap
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Login no Core via OAuth Device Code Flow:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
neetru login
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Validar estado:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
neetru doctor
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Quickstart — criar produto SaaS novo
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
neetru new gestovendas --env=dev --tier=dev --customer=neetru
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Cria produto + workspace + scaffold local Next.js 15 + instala deps + abre cockpit no browser.
|
|
43
|
+
|
|
44
|
+
## Comandos principais
|
|
45
|
+
|
|
46
|
+
| Comando | O que faz |
|
|
47
|
+
|---|---|
|
|
48
|
+
| `neetru bootstrap` | Setup da máquina dev (binários + deps + ADC) |
|
|
49
|
+
| `neetru login` / `logout` / `whoami` | Auth OAuth Device Code Flow |
|
|
50
|
+
| `neetru doctor` | Diagnóstico saúde (5 checks rápidos) |
|
|
51
|
+
| `neetru new <slug>` | Criar produto completo (registry + workspace + scaffold) |
|
|
52
|
+
| `neetru init <name>` | Só scaffold local Next.js + Firebase |
|
|
53
|
+
| `neetru add <feature>` | Adicionar features ao scaffold (auth, billing, etc) |
|
|
54
|
+
| `neetru deploy` | Pipeline de deploy interativo (cloud-run / vm / workspace) |
|
|
55
|
+
| `neetru build` | Empacotar produto em tarball pra deploy |
|
|
56
|
+
| `neetru promote` | Promover dev → staging → prod |
|
|
57
|
+
| `neetru env switch <target>` | Trocar `NEETRU_ENV` no `.env.local` |
|
|
58
|
+
| `neetru env set --service=X --set KEY=VAL` | Setar env vars de serviço Cloud Run |
|
|
59
|
+
| `neetru ar create <name>` | Criar repositório Artifact Registry |
|
|
60
|
+
| `neetru hosting create-mapping --service=X --domain=Y` | Domain mapping |
|
|
61
|
+
| `neetru db create --product=X --engine=postgres` | Criar banco por produto |
|
|
62
|
+
| `neetru db engines` | Listar engines disponíveis (firestore, postgres, mysql) |
|
|
63
|
+
| `neetru cloud-run pause/resume/delete <service>` | Controle Cloud Run |
|
|
64
|
+
| `neetru products list/create/update` | Registry de produtos |
|
|
65
|
+
| `neetru workspaces create/list/get/advance` | Instâncias por cliente |
|
|
66
|
+
| `neetru deployments create/rollback` | Histórico de deploys |
|
|
67
|
+
| `neetru tenants list/create/update/suspend` | Gerenciar tenants |
|
|
68
|
+
| `neetru audit tail` | Tail de `audit_logs/` em tempo real |
|
|
69
|
+
| `neetru billing summary` | Resumo de billing |
|
|
70
|
+
| `neetru servers list/provision/deactivate` | Gerenciar servidores |
|
|
71
|
+
| `neetru agent release/yank/canary` | Gerenciar releases do agente |
|
|
72
|
+
| `neetru support tickets list/reply/assign` | Suporte inbox staff |
|
|
73
|
+
| `neetru dns zones list` / `hosting list` | Listar DNS + customer domains |
|
|
74
|
+
| `neetru builds list` | Listar Cloud Build |
|
|
75
|
+
| `neetru dr exports/restore` | Disaster Recovery |
|
|
76
|
+
| `neetru logs` | Ver logs de produtos |
|
|
77
|
+
| `neetru status` | Visão geral do ecossistema |
|
|
78
|
+
| `neetru open <produto>` | Abrir cockpit do produto no browser |
|
|
79
|
+
| `neetru ai` | REPL IA Neetru-aware (Claude/OpenAI/Gemini) |
|
|
80
|
+
| `neetru ui` | Menu interativo do CLI |
|
|
81
|
+
| `neetru publish` | Publicar produto no catálogo público |
|
|
82
|
+
| `neetru fn deploy` | Deploy de Cloud Functions |
|
|
83
|
+
| `neetru upgrade` | Auto-update do CLI |
|
|
84
|
+
| `neetru autocomplete <bash\|zsh\|pwsh>` | Gerar script autocomplete |
|
|
85
|
+
|
|
86
|
+
**Atalhos:** `neetru ar` = `artifact-registry`, `neetru menu` = `ui`.
|
|
87
|
+
|
|
88
|
+
40+ subcomandos. Quase todos suportam `--json` pra automação.
|
|
89
|
+
|
|
90
|
+
## Configuração
|
|
91
|
+
|
|
92
|
+
Config persiste em `~/.config/neetru-cli/` (Linux/macOS) ou `%APPDATA%\neetru-cli\` (Windows):
|
|
93
|
+
|
|
94
|
+
| Chave | Valor |
|
|
95
|
+
|---|---|
|
|
96
|
+
| `neetruApiKey` | Token Bearer `nrt_<keyId>_<secret>` (gerado por `neetru login`) |
|
|
97
|
+
| `coreUrl` | URL base do Core (default `https://core.neetru.com`) |
|
|
98
|
+
| `telemetry.enabled` | Telemetry opt-in (default `false`) |
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
neetru config set telemetry.enabled true
|
|
102
|
+
neetru config get coreUrl
|
|
103
|
+
neetru config path # mostra caminho do config file
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Output JSON
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
neetru products list --json | jq '.[] | select(.status == "ativo")'
|
|
110
|
+
neetru audit tail --json | jq 'select(.action | startswith("billing"))'
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Auth & Segurança
|
|
114
|
+
|
|
115
|
+
- **OAuth Device Code Flow** (RFC 8628) pra login interativo — não armazena password
|
|
116
|
+
- **Tokens** salvos em `conf` cross-platform, permissões 0600 em Unix
|
|
117
|
+
- **Rate-limit** por método HTTP: GET 120/min, POST/PUT/PATCH 30/min, DELETE 5/min
|
|
118
|
+
- **Step-up MFA** (TOTP) obrigatório em operações destrutivas: `--mfa-token <code>` ou prompt
|
|
119
|
+
- **Dry-run** disponível em comandos de mutação: `--dry-run` mostra efeito SEM aplicar
|
|
120
|
+
|
|
121
|
+
## Stack
|
|
122
|
+
|
|
123
|
+
- TypeScript 5 ESM-first
|
|
124
|
+
- Node 22+ (LTS)
|
|
125
|
+
- Sem `node-fetch`/`axios`: fetch global nativo
|
|
126
|
+
- Commander 11 (CLI framework) + Inquirer 12 (prompts) + Chalk 5 + Ora (spinners)
|
|
127
|
+
|
|
128
|
+
## Mais info
|
|
129
|
+
|
|
130
|
+
- **Repo:** [github.com/Neetru/neetru-core](https://github.com/Neetru/neetru-core)
|
|
131
|
+
- **Docs:** [docs.neetru.com](https://docs.neetru.com)
|
|
132
|
+
- **SDK complementar:** `npm install @neetru/sdk`
|
|
133
|
+
- **Issues / suporte:** abrir issue no repo ou `neetru support`
|
|
134
|
+
|
|
135
|
+
## Licença
|
|
136
|
+
|
|
137
|
+
MIT © Neetru
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Indicador de passo: `step(2, 6, 'instalando')` → `"[2/6] instalando"`.
|
|
3
|
+
*
|
|
4
|
+
* `n` e `total` precisam ser inteiros com `1 <= n <= total`. Fora disso
|
|
5
|
+
* lança — um contador de passos inválido é bug de chamador, não algo a
|
|
6
|
+
* mascarar. `label` é coagido para string.
|
|
7
|
+
*/
|
|
8
|
+
export declare function step(n: number, total: number, label: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Opções de `errorBlock`.
|
|
11
|
+
*
|
|
12
|
+
* `fix` é OBRIGATÓRIO de propósito: torna invariante em tempo de compilação
|
|
13
|
+
* que todo bloco de erro carrega uma ação corretiva. Não existe erro sem
|
|
14
|
+
* "como resolver".
|
|
15
|
+
*/
|
|
16
|
+
export interface ErrorBlockOpts {
|
|
17
|
+
/** A ação corretiva — o que o usuário deve fazer para resolver. */
|
|
18
|
+
fix: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Bloco de erro multi-linha:
|
|
22
|
+
* `✗ <mensagem>`
|
|
23
|
+
* `→ Como resolver: <fix>`
|
|
24
|
+
*
|
|
25
|
+
* `message` e `fix` precisam ser strings não-vazias — se faltar qualquer um,
|
|
26
|
+
* lança. Todo erro DEVE dizer ao usuário como sair dele.
|
|
27
|
+
*/
|
|
28
|
+
export declare function errorBlock(message: string, opts: ErrorBlockOpts): string;
|
|
29
|
+
/**
|
|
30
|
+
* Opções da "pausa sagrada" — confirmação de operação destrutiva.
|
|
31
|
+
*/
|
|
32
|
+
export interface SacredPauseOpts {
|
|
33
|
+
/** O título da operação (ex.: "Migração destrutiva"). */
|
|
34
|
+
title: string;
|
|
35
|
+
/** O que será perdido — o dado/efeito irreversível. */
|
|
36
|
+
consequence: string;
|
|
37
|
+
/** Como o usuário confirma (ex.: "digite o nome do banco"). */
|
|
38
|
+
confirmHint: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Bloco visualmente destacado para a "pausa sagrada" de operações
|
|
42
|
+
* destrutivas. Renderiza um quadro delimitado por uma linha de `─` com:
|
|
43
|
+
* - `title` — em destaque (heading)
|
|
44
|
+
* - `consequence` — em amarelo (warn) — o que será perdido
|
|
45
|
+
* - `confirmHint` — como confirmar
|
|
46
|
+
*
|
|
47
|
+
* Os três campos são obrigatórios; vazio/espaço/não-string → lança.
|
|
48
|
+
*/
|
|
49
|
+
export declare function sacredPause(opts: SacredPauseOpts): string;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formatadores compostos da gramática visual do CLI.
|
|
3
|
+
*
|
|
4
|
+
* Funções puras: dado o mesmo input, devolvem o mesmo output (a estilização
|
|
5
|
+
* via `chalk` é determinística para um dado nível de cor). Todas devolvem
|
|
6
|
+
* strings — quem decide imprimir é o call site.
|
|
7
|
+
*/
|
|
8
|
+
import { GLYPHS } from './glyphs.js';
|
|
9
|
+
import { err, warn, dim, heading } from './palette.js';
|
|
10
|
+
/** Verdadeiro se `v` é string com pelo menos um caractere não-espaço. */
|
|
11
|
+
function isNonEmptyString(v) {
|
|
12
|
+
return typeof v === 'string' && v.trim().length > 0;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Indicador de passo: `step(2, 6, 'instalando')` → `"[2/6] instalando"`.
|
|
16
|
+
*
|
|
17
|
+
* `n` e `total` precisam ser inteiros com `1 <= n <= total`. Fora disso
|
|
18
|
+
* lança — um contador de passos inválido é bug de chamador, não algo a
|
|
19
|
+
* mascarar. `label` é coagido para string.
|
|
20
|
+
*/
|
|
21
|
+
export function step(n, total, label) {
|
|
22
|
+
if (!Number.isInteger(n) || !Number.isInteger(total)) {
|
|
23
|
+
throw new Error(`step(): n e total precisam ser inteiros — recebido n=${n}, total=${total}`);
|
|
24
|
+
}
|
|
25
|
+
if (total < 1) {
|
|
26
|
+
throw new Error(`step(): total precisa ser >= 1 — recebido total=${total}`);
|
|
27
|
+
}
|
|
28
|
+
if (n < 1 || n > total) {
|
|
29
|
+
throw new Error(`step(): n precisa estar entre 1 e ${total} — recebido n=${n}`);
|
|
30
|
+
}
|
|
31
|
+
const text = typeof label === 'string' ? label : String(label);
|
|
32
|
+
return `[${n}/${total}] ${text}`;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Bloco de erro multi-linha:
|
|
36
|
+
* `✗ <mensagem>`
|
|
37
|
+
* `→ Como resolver: <fix>`
|
|
38
|
+
*
|
|
39
|
+
* `message` e `fix` precisam ser strings não-vazias — se faltar qualquer um,
|
|
40
|
+
* lança. Todo erro DEVE dizer ao usuário como sair dele.
|
|
41
|
+
*/
|
|
42
|
+
export function errorBlock(message, opts) {
|
|
43
|
+
if (!isNonEmptyString(message)) {
|
|
44
|
+
throw new Error('errorBlock(): message precisa ser uma string não-vazia');
|
|
45
|
+
}
|
|
46
|
+
if (!opts || !isNonEmptyString(opts.fix)) {
|
|
47
|
+
throw new Error('errorBlock(): opts.fix precisa ser uma string não-vazia — todo erro precisa de uma ação corretiva');
|
|
48
|
+
}
|
|
49
|
+
const headLine = `${err(GLYPHS.err)} ${err(message)}`;
|
|
50
|
+
const fixLine = `${dim(GLYPHS.arrow)} ${dim('Como resolver:')} ${opts.fix}`;
|
|
51
|
+
return `${headLine}\n${fixLine}`;
|
|
52
|
+
}
|
|
53
|
+
/** Largura da borda do bloco de pausa sagrada. */
|
|
54
|
+
const SACRED_PAUSE_WIDTH = 56;
|
|
55
|
+
/**
|
|
56
|
+
* Bloco visualmente destacado para a "pausa sagrada" de operações
|
|
57
|
+
* destrutivas. Renderiza um quadro delimitado por uma linha de `─` com:
|
|
58
|
+
* - `title` — em destaque (heading)
|
|
59
|
+
* - `consequence` — em amarelo (warn) — o que será perdido
|
|
60
|
+
* - `confirmHint` — como confirmar
|
|
61
|
+
*
|
|
62
|
+
* Os três campos são obrigatórios; vazio/espaço/não-string → lança.
|
|
63
|
+
*/
|
|
64
|
+
export function sacredPause(opts) {
|
|
65
|
+
if (!opts) {
|
|
66
|
+
throw new Error('sacredPause(): opts é obrigatório');
|
|
67
|
+
}
|
|
68
|
+
if (!isNonEmptyString(opts.title)) {
|
|
69
|
+
throw new Error('sacredPause(): title precisa ser uma string não-vazia');
|
|
70
|
+
}
|
|
71
|
+
if (!isNonEmptyString(opts.consequence)) {
|
|
72
|
+
throw new Error('sacredPause(): consequence precisa ser uma string não-vazia');
|
|
73
|
+
}
|
|
74
|
+
if (!isNonEmptyString(opts.confirmHint)) {
|
|
75
|
+
throw new Error('sacredPause(): confirmHint precisa ser uma string não-vazia');
|
|
76
|
+
}
|
|
77
|
+
const border = dim('─'.repeat(SACRED_PAUSE_WIDTH));
|
|
78
|
+
const lines = [
|
|
79
|
+
border,
|
|
80
|
+
`${warn(GLYPHS.warn)} ${heading(opts.title)}`,
|
|
81
|
+
'',
|
|
82
|
+
`${GLYPHS.bullet} ${warn(opts.consequence)}`,
|
|
83
|
+
`${GLYPHS.arrow} ${opts.confirmHint}`,
|
|
84
|
+
border,
|
|
85
|
+
];
|
|
86
|
+
return lines.join('\n');
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/cli-kit/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Glifos canônicos da gramática visual do CLI.
|
|
3
|
+
*
|
|
4
|
+
* Conjunto pequeno e fechado de símbolos usados em toda a saída do
|
|
5
|
+
* `@neetru/cli`. Congelado para que nenhum comando reescreva um glifo no
|
|
6
|
+
* meio do caminho — a consistência visual é parte do contrato.
|
|
7
|
+
*/
|
|
8
|
+
export declare const GLYPHS: Readonly<{
|
|
9
|
+
/** Sucesso / passo concluído. */
|
|
10
|
+
ok: "✓";
|
|
11
|
+
/** Erro / falha. */
|
|
12
|
+
err: "✗";
|
|
13
|
+
/** Aviso / atenção. */
|
|
14
|
+
warn: "⚠";
|
|
15
|
+
/** Encaminhamento / próxima ação (ex.: linha de "como resolver"). */
|
|
16
|
+
arrow: "→";
|
|
17
|
+
/** Item de lista. */
|
|
18
|
+
bullet: "·";
|
|
19
|
+
/** Em andamento / pendente. */
|
|
20
|
+
pending: "…";
|
|
21
|
+
}>;
|
|
22
|
+
export type Glyphs = typeof GLYPHS;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Glifos canônicos da gramática visual do CLI.
|
|
3
|
+
*
|
|
4
|
+
* Conjunto pequeno e fechado de símbolos usados em toda a saída do
|
|
5
|
+
* `@neetru/cli`. Congelado para que nenhum comando reescreva um glifo no
|
|
6
|
+
* meio do caminho — a consistência visual é parte do contrato.
|
|
7
|
+
*/
|
|
8
|
+
export const GLYPHS = Object.freeze({
|
|
9
|
+
/** Sucesso / passo concluído. */
|
|
10
|
+
ok: '✓',
|
|
11
|
+
/** Erro / falha. */
|
|
12
|
+
err: '✗',
|
|
13
|
+
/** Aviso / atenção. */
|
|
14
|
+
warn: '⚠',
|
|
15
|
+
/** Encaminhamento / próxima ação (ex.: linha de "como resolver"). */
|
|
16
|
+
arrow: '→',
|
|
17
|
+
/** Item de lista. */
|
|
18
|
+
bullet: '·',
|
|
19
|
+
/** Em andamento / pendente. */
|
|
20
|
+
pending: '…',
|
|
21
|
+
});
|
|
22
|
+
//# sourceMappingURL=glyphs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glyphs.js","sourceRoot":"","sources":["../../src/cli-kit/glyphs.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAClC,iCAAiC;IACjC,EAAE,EAAE,GAAG;IACP,oBAAoB;IACpB,GAAG,EAAE,GAAG;IACR,uBAAuB;IACvB,IAAI,EAAE,GAAG;IACT,qEAAqE;IACrE,KAAK,EAAE,GAAG;IACV,qBAAqB;IACrB,MAAM,EAAE,GAAG;IACX,+BAA+B;IAC/B,OAAO,EAAE,GAAG;CACb,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@neetru/cli-kit` — gramática visual do `@neetru/cli`.
|
|
3
|
+
*
|
|
4
|
+
* Primitivos de saída no terminal: glifos canônicos, paleta semântica e
|
|
5
|
+
* formatadores compostos. Todo comando do CLI deve usar este módulo em vez
|
|
6
|
+
* de chamar `chalk` direto — assim a identidade visual é consistente e
|
|
7
|
+
* evolui num lugar só.
|
|
8
|
+
*/
|
|
9
|
+
export { GLYPHS } from './glyphs.js';
|
|
10
|
+
export type { Glyphs } from './glyphs.js';
|
|
11
|
+
export { ok, err, warn, dim, heading } from './palette.js';
|
|
12
|
+
export { step, errorBlock, sacredPause, } from './format.js';
|
|
13
|
+
export type { ErrorBlockOpts, SacredPauseOpts } from './format.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@neetru/cli-kit` — gramática visual do `@neetru/cli`.
|
|
3
|
+
*
|
|
4
|
+
* Primitivos de saída no terminal: glifos canônicos, paleta semântica e
|
|
5
|
+
* formatadores compostos. Todo comando do CLI deve usar este módulo em vez
|
|
6
|
+
* de chamar `chalk` direto — assim a identidade visual é consistente e
|
|
7
|
+
* evolui num lugar só.
|
|
8
|
+
*/
|
|
9
|
+
export { GLYPHS } from './glyphs.js';
|
|
10
|
+
export { ok, err, warn, dim, heading } from './palette.js';
|
|
11
|
+
export { step, errorBlock, sacredPause, } from './format.js';
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli-kit/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE3D,OAAO,EACL,IAAI,EACJ,UAAU,EACV,WAAW,GACZ,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Sucesso — verde. */
|
|
2
|
+
export declare function ok(s: string): string;
|
|
3
|
+
/** Erro — vermelho. */
|
|
4
|
+
export declare function err(s: string): string;
|
|
5
|
+
/** Aviso — amarelo. */
|
|
6
|
+
export declare function warn(s: string): string;
|
|
7
|
+
/** Texto secundário / esmaecido. */
|
|
8
|
+
export declare function dim(s: string): string;
|
|
9
|
+
/** Título de seção — negrito. */
|
|
10
|
+
export declare function heading(s: string): string;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paleta semântica do CLI — wrappers finos de `chalk`.
|
|
3
|
+
*
|
|
4
|
+
* Cada função recebe uma string e devolve a string estilizada. A intenção é
|
|
5
|
+
* semântica (ok / err / warn / dim / heading), nunca "pinte de verde" — assim
|
|
6
|
+
* a paleta pode evoluir sem tocar nos call sites.
|
|
7
|
+
*
|
|
8
|
+
* Defensivo: entrada não-string é coagida com `String(...)` em vez de lançar —
|
|
9
|
+
* estilizar texto nunca deve derrubar o CLI.
|
|
10
|
+
*/
|
|
11
|
+
import chalk from 'chalk';
|
|
12
|
+
/** Coage qualquer valor para string sem lançar. */
|
|
13
|
+
function coerce(s) {
|
|
14
|
+
return typeof s === 'string' ? s : String(s);
|
|
15
|
+
}
|
|
16
|
+
/** Sucesso — verde. */
|
|
17
|
+
export function ok(s) {
|
|
18
|
+
return chalk.green(coerce(s));
|
|
19
|
+
}
|
|
20
|
+
/** Erro — vermelho. */
|
|
21
|
+
export function err(s) {
|
|
22
|
+
return chalk.red(coerce(s));
|
|
23
|
+
}
|
|
24
|
+
/** Aviso — amarelo. */
|
|
25
|
+
export function warn(s) {
|
|
26
|
+
return chalk.yellow(coerce(s));
|
|
27
|
+
}
|
|
28
|
+
/** Texto secundário / esmaecido. */
|
|
29
|
+
export function dim(s) {
|
|
30
|
+
return chalk.dim(coerce(s));
|
|
31
|
+
}
|
|
32
|
+
/** Título de seção — negrito. */
|
|
33
|
+
export function heading(s) {
|
|
34
|
+
return chalk.bold(coerce(s));
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=palette.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"palette.js","sourceRoot":"","sources":["../../src/cli-kit/palette.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,mDAAmD;AACnD,SAAS,MAAM,CAAC,CAAU;IACxB,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,uBAAuB;AACvB,MAAM,UAAU,EAAE,CAAC,CAAS;IAC1B,OAAO,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,uBAAuB;AACvB,MAAM,UAAU,GAAG,CAAC,CAAS;IAC3B,OAAO,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC;AAED,uBAAuB;AACvB,MAAM,UAAU,IAAI,CAAC,CAAS;IAC5B,OAAO,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACjC,CAAC;AAED,oCAAoC;AACpC,MAAM,UAAU,GAAG,CAAC,CAAS;IAC3B,OAAO,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC;AAED,iCAAiC;AACjC,MAAM,UAAU,OAAO,CAAC,CAAS;IAC/B,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/B,CAAC"}
|
package/dist/commands/ai.js
CHANGED
|
@@ -9,14 +9,14 @@ const PROMPT_PREFIX = chalk.hex('#1E90FF').bold(' › ');
|
|
|
9
9
|
const ASSISTANT_PREFIX = chalk.dim(' ◆ ');
|
|
10
10
|
// Help público — sem /modelo (orchestrator escolhe). /debug:model é o
|
|
11
11
|
// override avançado pra quem quer forçar.
|
|
12
|
-
const HELP_TEXT = `
|
|
13
|
-
Comandos:
|
|
14
|
-
/sair /exit encerrar sessão
|
|
15
|
-
/limpar /clear limpar histórico de contexto
|
|
16
|
-
/agentes <pergunta> consultar 2+ modelos em paralelo e comparar
|
|
17
|
-
/auth rodar wizard de configuração (claude/codex/gemini)
|
|
18
|
-
/help mostrar este texto
|
|
19
|
-
/debug:model <nome> forçar modelo (claude|openai|gemini|auto)
|
|
12
|
+
const HELP_TEXT = `
|
|
13
|
+
Comandos:
|
|
14
|
+
/sair /exit encerrar sessão
|
|
15
|
+
/limpar /clear limpar histórico de contexto
|
|
16
|
+
/agentes <pergunta> consultar 2+ modelos em paralelo e comparar
|
|
17
|
+
/auth rodar wizard de configuração (claude/codex/gemini)
|
|
18
|
+
/help mostrar este texto
|
|
19
|
+
/debug:model <nome> forçar modelo (claude|openai|gemini|auto)
|
|
20
20
|
`.trim();
|
|
21
21
|
/**
|
|
22
22
|
* Checa se o usuário tem pelo menos uma cred (local OU descoberta). Se zero,
|